Project update 4 of 6
The Tinusaur OLED Display has two main components: the ATtiny85 microcontroller and the SSD1306 OLED display controller. The SSD1306 chip is a popular choice for controlling OLED displays, which are readily available online.
Such displays can be used to display any number of things, from basic text and numbers, to complex game animations. Back in 2014, we wrote a small, open source library, called SSD1306xLED, for the ATtiny85 microcontroller to work with SSD1306-powered OLED displays. The Tinusaur OLED Display project is a perfect hardware companion to the library.
The SSD1306xLED library works with OLED display modules that use the I2C protocol. There are similar displays that use the same SSD1306 controller but communicate over the SPI interface. Our library does not work with the SPI version of the controller chip. In most cases, you can tell that a SSD1306 controller uses I2C if it has four pins – GND, VCC, SCL, SDA.
Although using the I2C interface, our SSD1306xLED library does not implement the full I2C protocol, but rather just enough of it to send commands and data to the display. In particular, the library does not support reading state back from the display. This comes with two great advantages: 1) it is super fast, and 2) it is super small. Read on for more details. The library is, of course, open source and all the software is available at https://bitbucket.org/tinusaur/ssd1306xled/.
This is a small sub-library used in SSD1306xLED that implements the subset of the I2C protocol necessary to send commands and data out. As its name implies, the I2CSW library only writes out.
For the purpose of communicating with the SSD1306 controller, writing to it is enough, since the controller does not send any data back. The downside is that the same library cannot be used to receive data from another device, such as I2C sensor modules.
There are two macros to set the SCL and SDA wires to high and to low (1 and 0):
I2CSW_HIGH(PORT)
I2CSW_LOW(PORT)
There are also three low-level functions:
void i2csw_start(void);
void i2csw_stop(void);
void i2csw_byte(uint8_t byte);
The i2csw_start
function sets the SCL and SDA pins as outputs and the "start" condition. In other words, it lets the devices connected to the microcontroller know that we are about to send something out.
The i2csw_stop
function sets the "stop" condition, which indicates we have finished sending data. It also sets the SDA pin as input so it won’t keep the SDA line HIGH all the time.
The i2csw_byte
function sends one byte of data out. It is used to send commands and data to the I2C devices – the display in our case.
Note that the I2CSW library does not handle the acknowledgment condition.
There are four core functions in the library at the moment:
void ssd1306_start_command(void);
void ssd1306_start_data(void);
void ssd1306_data_byte(uint8_t);
void ssd1306_stop(void);
The ssd1306_start_command
function indicates to the connected I2C devices that we’re about to send commands. This is used to configure the controller or to set some parameters such as the current position on the display.
The ssd1306_start_data
function indicates to the connected I2C devices that we’re about to send some data. This is used to send some data to the display controller – like bitmaps or text.
The ssd1306_data_byte
function sends two bytes of data to the display controller. This function is used for both commands and data.
Finally, the ssd1306_stop
function indicates that we have finished transmitting data.
These are three convenience functions:
void ssd1306_init(void);
void ssd1306_setpos(uint8_t x, uint8_t y);
void ssd1306_fill4(uint8_t, uint8_t, uint8_t, uint8_t);
The ssd1306_init
function sends a sequence of commands that will initialize the display controller so it will work the way we expect.
The ssd1306_setpos
function sets the current position on the display. Sending data after this command will display it at that position. From the SSD1306 documentation (Solomon Systech Apr 2008 P 42/59 Rev 1.1 SSD1306):
Horizontal addressing mode (A[1:0]=00b)
In horizontal addressing mode, after the display RAM is
read/written, the column address pointer is increased automatically
by 1. If the column address pointer reaches column end address, the
column address pointer is reset to column start address and page
address pointer is increased by 1. The sequence of movement of the
page and column address point for horizontal addressing mode is
shown in Figure 10-3. When both column and page address pointers
reach the end address, the pointers are reset to column start
address and page start address (Dotted line in Figure 10-3.)
We are using the horizontal addressing mode since it is the most convenient for drawing shapes or printing characters.
The ssd1306_fill4
function fills out the screen with the four bytes specified as parameters. The reason for four bytes is that it is convenient for filling the screen with patterns.
There are three other functions derived from the ssd1306_fill4
function:
ssd1306_clear()
clears the screen, i.e., fills it with zeroesssd1306_fill(p)
fills the display with the specified bytessd1306_fill2(p1, p2)
fills the display with the two specified bytesThe testing script in the ssd1306xled_test1
folder demonstrates the purpose and usage of the library.
The first section of this file fills out the screen with random values using a linear congruential generator. The second section fills out the screen with a sequential number that creates some patterns. The next section fills the screen line by line. The last section fills out the screen with various patterns.
There are more functions in the SSD1306xLED library, such as for printing text and numbers on the screen and drawing images, but those will be subject of another update. In the meantime, here are images of the various patterns generated by the tests described above: