A Swift library for OLED displays based on SSD1306 and SSD1305 drivers. It is just a set of functions for handling mentioned aboved drivers. It is not a graphics library. For that I would like to recommend a SwiftyGFX, which I will be using here as an example. However you are free to use your own.
In this section you will create your first project
- Wire the display
- Make sure you know to which I2C interface you have wired the display
- Make sure you are aware of a I2C address of display module you have. For most cases it will be 0x3C or 0x3D. If you are unsure run
sudo apt-get install i2c-tools && sudo i2cdetect -y 1
. Confused? take a look here - Create new project with SwiftPM like
swift package init --type executable
In your Package.swift file:
- Add the following packages as dependencies
.package(url: "https://github.com/3Qax/SwiftyOLED.git", from: "1.0.0"),
.package(url: "https://github.com/3Qax/SwiftyGFX.git", from: "1.0.0"),
.package(url: "https://github.com/uraimo/SwiftyGPIO.git", from: "1.0.0"),
- Show SwiftPM that your target will need those dependencies
.target(
name: "NameOfYourProject",
dependencies: ["SwiftyOLED", "SwiftyGFX", "SwiftyGPIO"]),
Paste the following code into your source file, which most likely will be in Sources/NameOfYourProject/main.swift. Change I2C Interface and I2C address if needed. Set width and height of your display according to specification of model you have bought.
import SwiftyOLED
import SwiftyGFX
import SwiftyGPIO
let i2cs = SwiftyGPIO.hardwareI2Cs(for: .RaspberryPiPlusZero)!
// Make sure you entered a correct parameters below
let myOLED = OLED(connectedTo: i2cs[1], at: 0x3C, width: 128, height: 32)
let myText = Text("Hello world!")
myOLED.draw(points: myText.generatePointsForDrawing())
myOLED.display()
Just do swift build
and then swift run
. You should see:
That's all. It's really that simple! Complete project can be found in /Examples/hello world/ folder.
To create the instance of OLED use the follwoing initializer
public init(connectedTo interface: I2CInterface, at address: Int, width: Int, height: Int)
Pass the I2C interface that display is connected to and specify at which address device listens. Enter the width and height (in px) based on the specification of display you have. Probably it will be 128x32 or 128x64. Initialization will fail on runtime if display is unreachable or if given height or width doesn't make sense (exceed driver supported range).
If you don't feel like writing your graphics library today, take a look at my easy to use graphics library SwiftyGFX. It provides a bunch of primitives like Circles and Rectangles, but is also capable of text rendering. See it's README.md for details.
Once you've got the reference to the display it's time to draw something! This can be done by calling one of these methods
public func draw(point: (Int, Int))
public func draw(points: [(Int, Int)])
Doing so changes the color of point or points at given coordinates to white in local buffer. This means that drawn points will be not visible until calling display()
.
The display works in iOS like coordinate system. So:
- (0, 0) is top left pixel
- X axis increases to the right
- Y axis increases downwards
Point consists of (respectively) x and y coordinates
If you would like to clean (make black) the local buffer do it like
public func clear()
Or if you are on the light side of force this method might come in handy
public func fill()
In order to draw things in black on white display use above mentioned methods and set the display to interprete everything inversly. Logically, clear()
will make whole local buffer white and drawing would make given points black. It is as simple as calling
public func set(inversion: Bool)
By default it off. You can check wether display is inverted by accessing read only property called isInverted
.
Once you have drawn everything you wanted and want to make it visible call
public func display()
This will make display reflect the actual state of local buffer. After that local buffer will be cleared. The API is designed is such a way, because transfering data over I2C is quite slow operation. Call this method only after you have drawn everything.
There is even an option to change the brightness by calling
public func set(brightness: Brightness)
There are two recomended setting: .dimmed
or .bright
, however if you wish so you can set custom level like .custom(value: 0x8F)
If your project requires low power consumption or showing data on display only from time to time take a look at
public func turn(_ state: State)
It allows you to either turn it .on
or .off
. Display is configured to display the latest data it have recived on resume (turn on after being turned off). The display after being initialized is automatically turned on. Display's state is stored in read only property called isOn
.
Performance was tested on geniune RaspberryPi ZERO v1.3 running Raspbian Stretch Lite using SwiftyGPIO 1.1.7.
Display size (px) | Avarege time of display() |
---|---|
96x16 | 7ms |
128x32 | 16ms |
128x64 | 32ms |
Any suggestions and contributions are welcome, as long as they are up to scratch.
- This library use, require and rely on SwiftyGPIO
- Big inspiration and a lot of knowledge was taken from a Adafruit CircuitPython library for SSD1306