-
-
Notifications
You must be signed in to change notification settings - Fork 21
Getting Started
One of the most frequently asked questions is - "Why isn't there a true print function included in the library?" Many display libraries include a print/printf/println function to mimic the features of the Arduino Serial library. The reason I didn't include it is because it goes against one of the goals of the library - small code size. By adding a formatted print function, it would necessarily add a dependency on printf() or I would need to write similar code. If you need to print formatted output of numbers, strings, etc, you can do it like this:
char szTemp[32];
sprintf(szTemp, "My value = %d", myValue);
obdWriteString(&obd, 0,0,0, szTemp, FONT_NORMAL, 0 1);
The printf() functions in the C runtime library are pretty large and I didn't want them to be a forced dependency within OneBitDisplay.
Microcontrollers often have meager resources available (RAM/ROM) and one of the goals of OneBitDisplay is to minimize the size of the code, font data and RAM usage. The majority of serial (I2C/SPI) displays are write-only; this means that we can't read back the data after it's written. For some operations (e.g. drawing lines) the new pixels need to be combined with the existing pixels on the display. If we're unable to read the display memory, how can we combine new and old pixels? The answer is to create a "back buffer" which has a copy of the display memory in our local memory. A 128x64 1 bit per pixel display needs (128x64)/8 = 1024 bytes. On the simplest of MCUs (ATtiny series), they usually have less than that amount of RAM. This means that we can't keep a copy of the display in memory and are limited to write-only operations such as drawing text which overwrites the background pixels. On 'larger' MCUs like the ARM Cortex-M, ESP32 and newer AVRs, there is enough RAM to keep a copy of the back buffer. This brings us back to the render flag. On systems which support a back buffer, it can be a speed advantage to prepare your drawing in memory, then write it to the display at a later time. The OneBitDisplay functions support this option through the render flag. Setting the render flag to true (1) tells the library to transmit the data immediately to the display (and keep a copy in memory if there is a back buffer). If you do operations with the render flag set to false (0), they'll only occur on the back buffer and when you're ready to display it, call the obdDumpBuffer() function.
The simplest displays to connect use I2C since they only require 2 wires for communication (clock and data). There are still a number of options that need to be specified to get started. Here's the I2C initialization function:
int obdI2CInit(OBDISP *pOBD, int iType, int iAddr, int bFlip, int bInvert, int bWire, int sda, int scl, int reset, int32_t iSpeed)
pOBD - Pointer to a OBDISP structure. This holds the unique info for your display. The OneBitDisplay library can manage any number of displays simultaneously, so your MCU can control one or more at a time.
iType - The display type defined in OneBitDisplay.h. For I2C, this can be one of the OLED_xxx defines (e.g. OLED_128x64).
iAddr - The I2C address of your display. Most OLEDs are at 0x3C or 0x3D. You can also set this to -1 and it will automatically detect the address of your display (if there is only 1 on the I2C bus).
bFlip - A boolean indicating where the display is in the normal orientation (0) or flipped 180 degrees (1).
bInvert - OLEDs and LCDs have an option to invert the colors. This is implemented in hardware and not done by OneBitDisplay.
.
bWire - This parameter tells the library to use hardware I2C (the Wire library) or software (bit-banging of the signals on GPIO pins). For practical purposes, there's not a big difference between the two. On certain MCUs (e.g. AVR), the Wire library limits the max speed to 400Khz even though the display is capable of handling a much faster signal. Some MCUs like the ESP32 have more flexible pin definitions and can do hardware I2C on various pins. In that case, you can specify the specific pin numbers to use. To use the default I2C pins, specify -1 for both SDA and SCL. When bWire is false (0), you must specify valid GPIO pin numbers for SDA and SCL.
sda - As described above, this specifies the GPIO pin number for the SDA signal. If you set bWire to true (1) and want to use the default I2C pins, you can set this to -1.
scl - As described above, this specifies the GPIO pin number for the SCL signal. If you set bWire to true (1) and want to use the default I2C pins, you can set this to -1.
reset - The GPIO pin used to reset the display. Some OLED displays configured for I2C require this signal, others do the reset automatically and don't need it. Set this to -1 if your display doesn't have a reset pin exposed.
iSpeed - The I2C clock speed. 'normal' I2C speed is 100Khz, 'fast' is 400Khz. All of the OLEDs I've tested can handle much faster signals. On ESP32 you can set this as high as 800Khz, on ARM Cortex-M, the MCUs I've tested allow you to specify almost any speed, but the displays usually stop working above 1.6Mhz depending on the wiring and pull-up resistors used.
So, here's a simple example of initializing a 128x64 OLED connected to the default I2C bus on any MCU:
OBDISP obd;
obdI2CInit(&obd, OLED_128x64, -1, 0, 0, 1, -1, -1, -1, 400000L);
Text drawing is not as advanced as other features. Currently, OneBitDisplay uses fixed fonts and only allows drawing them on byte boundaries. There are however some advanced features present such as fine horizontal scrolling and delayed rendering. Here's the one function for drawing text:
int obdWriteString(OBDISP *pOBD, int iScrollX, int x, int y, char *szMsg, int iSize, int bInvert, int bRender)
pOBD - Pointer to a OBDISP structure
iScrollX - A scroll offset representing the number of pixels to scroll the text to the left. For example, if the 8x8 font is used and this value is 4, then the left half of the first character will not be visible.
x - The column to start drawing the text (starting from 0). On a 128x64 display, this value can be 0-127.
y - The byte row to start drawing the text. On a 128x64 display there are 8 byte rows (64/8), so this value can be 0-7.
szMsg - Zero terminated (C String) containing the text to draw. Text which would run off the right edge of the display will continue to be drawn on the next line of word wrap is enabled (see obdSetTextWrap).
iSize - This specifies one of the enumerated font size values (e.g. FONT_NORMAL).
bInvert - Flag to invert the color of the characters and background.
bRender - Flag indicating if the text will be drawn immediately on the display (true) or just to a backing buffer (false). If no backing buffer is defined, this will be set to true.
example - write the words "Hello World" on the first line of the display with the 8x8 font:
obdWriteString(&obd, 0,0,0, (char *)"Hello World", FONT_NORMAL, 0, 1);