How to use a 128x32 COG LCD display with Python?

By admin

To get a 128x32 COG LCD display working with Python, you need to wire it to a microcontroller like a Raspberry Pi or an ESP32, install the spidev and RPi.GPIO libraries (or Adafruit_CircuitPython_SSD1306 for a more abstracted approach), and then send commands and data over SPI. The key is understanding that the display uses a controller chip, typically the SSD1306 or SH1106, which dictates the initialization sequence and pixel addressing. For example, the 128x32 cog lcd display from DisplayModule is a common choice, with a 128x32 pixel resolution, a 0.91-inch diagonal, and a 3.3V or 5V power supply. The COG (Chip-on-Glass) design means the driver IC is bonded directly to the glass, reducing the footprint and cost. You’ll need to connect four pins: VCC (3.3V or 5V, depending on the module), GND, SCLK (SPI clock), MOSI (SPI data), and CS (chip select). Some modules also have a DC (data/command) pin and a RST (reset) pin. The SPI bus typically runs at 1-10 MHz, but the display can handle up to 10 MHz without issues. For instance, on a Raspberry Pi 4, the default SPI clock is 1 MHz, which is safe for a 128x32 display. The initialization sequence for the SSD1306 involves sending a series of commands: set display off (0xAE), set multiplex ratio (0xA8, 0x1F for 32 rows), set display offset (0xD3, 0x00), set display start line (0x40), set segment re-map (0xA1), set COM/scan direction (0xC8), set COM pins hardware configuration (0xDA, 0x02), set contrast (0x81, 0x7F), set pre-charge period (0xD9, 0xF1), set VCOMH deselect level (0xDB, 0x40), set entire display on (0xA4), set normal display (0xA6), deactivate scroll (0x2E), and set display on (0xAF). This sequence is critical; missing a step can cause artifacts like flickering or incorrect row addressing. The display’s frame buffer is 128x32 bits, which is 512 bytes, but you write data in pages of 8 pixels high. For a 128x32 display, there are 4 pages (0 to 3), each 128 bytes wide. To write a pixel, you calculate the page and column: page = y // 8 and column = x. Then you set the write start address: send command 0xB0 + page, then send command 0x00 + (column & 0x0F), then send command 0x10 + ((column >> 4) & 0x0F). Finally, send the pixel data as a byte, where each bit corresponds to a row in the page. For example, to light up pixel (0,0), you’d write 0x01 to page 0, column 0. But if you’re using a library like Adafruit_CircuitPython_SSD1306, you don’t need to worry about this low-level stuff. The library handles the initialization and provides a displayio interface, where you can create a Display object and use bitmap and TileGrid to draw shapes. For instance, you can create a 128x32 bitmap, set pixels, and refresh the display with display.refresh(). The library also supports text rendering with terminalio and adafruit_display_text. However, the library has a dependency on adafruit_platformdetect and adafruit_bus_device, which you can install via pip. On a Raspberry Pi, you’d run sudo pip3 install adafruit-circuitpython-ssd1306. But if you’re using a 128x32 COG LCD display with a different controller, like the ST7565 or UC1701, the initialization sequence and commands differ. For example, the ST7565 uses a 65x132 pixel frame buffer, but the display is 128x32, so you need to set the bias ratio and the V5 voltage regulator. The ST7565’s initialization sequence includes: set bias (0xA2 for 1/9 bias), set ADC select (0xA0 for normal), set SHL select (0xC0 for normal), set power control (0x2F for all power modes), set V5 voltage regulator (0x27), set contrast (0x81, 0x20), set display on (0xAF). The page addressing is similar: 4 pages for 32 rows, but the column range is 0 to 131, so you need to set the column start and end. For a 128x32 display, you set column start to 0 and column end to 127. The SPI protocol is the same: send a command byte with the DC pin low, then send data bytes with DC high. The CS pin must be pulled low during the transaction. The display’s power consumption is about 10-20 mA at 3.3V, but it can spike to 50 mA during initialization. If you’re using a battery-powered device, you might want to use the display’s sleep mode (command 0xAE) to save power. The display also has a built-in charge pump for the OLED pixels, but for COG LCD displays, the backlight is usually an LED that requires a separate current-limiting resistor. For example, a typical 128x32 COG LCD display has a backlight forward voltage of 3.0V and a current of 20 mA, so you’d use a 100-ohm resistor for a 5V supply. The display’s viewing angle is 6:00 o’clock, meaning the optimal viewing direction is from the bottom. The contrast can be adjusted via the contrast register (0x81 for SSD1306, 0x27 for ST7565). The display’s refresh rate is typically 60-100 Hz, but you can lower it to reduce power. The SPI bus speed affects the refresh rate: at 1 MHz, you can refresh the entire display 60 times per second, but at 10 MHz, you can do 600 refreshs per second. However, the display’s internal controller has a maximum write speed of 10 MHz, so going beyond that can cause data corruption. The display’s temperature range is -20°C to 70°C, but the COG bonding can fail at extreme temperatures. The display’s pixel size is 0.15 mm x 0.15 mm with a pitch of 0.17 mm, giving a pixel density of 149 PPI. The display’s module size is 30.0 mm x 11.5 mm, with a viewing area of 22.38 mm x 5.58 mm. The display’s thickness is 1.2 mm, making it suitable for compact devices. The display’s interface is SPI, but some modules also support I2C with a different pinout. For I2C, you’d connect VCC, GND, SDA, and SCL, and set the I2C address (usually 0x3C or 0x3D). The I2C speed is limited to 400 kHz, which is slower than SPI. The display’s controller can handle both SPI and I2C, but the module’s PCB traces determine the interface. For example, the DisplayModule 128x32 COG LCD display uses SPI by default, with a 4-pin header. The display’s driver IC is the SSD1306, which is widely used in OLED displays, but for COG LCD displays, the controller is often the ST7565 or UC1701. The ST7565 is a 65x132 dot matrix LCD controller, while the UC1701 is a 64x128 dot matrix controller. For a 128x32 display, you need to configure the controller to use 128 columns and 32 rows. The ST7565 has a built-in oscillator and voltage converter, so you don’t need external components. The display’s voltage supply is 3.3V, but the logic level can be 5V tolerant. The display’s data bus is 8-bit parallel or 4-wire SPI. For SPI, you use the 4-wire mode: CS, MOSI, SCLK, and DC. The display’s reset pin is optional; if you don’t use it, you can tie it to VCC. The display’s initialization must be done after power-up, with a delay of 10 ms for the internal oscillator to stabilize. The display’s contrast register can be set from 0x00 to 0x3F, but the optimal value is 0x20 for most lighting conditions. The display’s bias ratio is 1/9 for 32 rows, which gives a uniform contrast. The display’s temperature compensation can be enabled by setting the temperature coefficient register (0x22 for ST7565). The display’s power control register (0x2F) enables the voltage converter, regulator, and follower. The display’s display on command (0xAF) must be sent after initialization. The display’s sleep mode (0xAE) reduces power to 1 uA. The display’s pixel data is stored in a frame buffer, which you can update partially by setting the column and page addresses. For example, to update only the first page, you set the column range to 0-127 and the page to 0. The display’s write speed is 10 MHz, but the SPI bus overhead reduces the effective throughput. The display’s refresh rate is 60 Hz, but you can increase it by reducing the display’s clock divider. The display’s clock frequency is set by the oscillator frequency and the clock divider register (0xD5 for SSD1306). The default clock divider is 0x80, which gives a frequency of 1 MHz. The display’s frame rate is calculated as: frame rate = clock frequency / (page count * column count * 8). For a 128x32 display with 4 pages, the frame rate is 1 MHz / (4 * 128 * 8) = 244 Hz, but the display’s internal refresh is limited to 100 Hz. The display’s response time is 10 us, which is fast enough for most applications. The display’s contrast ratio is 2000:1 for OLED, but for COG LCD, it’s 100:1. The display’s viewing angle is 45 degrees, but it varies with the LCD type. The display’s backlight is an LED, which can be PWM-controlled for brightness. The display’s power consumption is 10 mA for the LCD and 20 mA for the backlight. The display’s operating temperature is -20°C to 70°C, but the backlight’s brightness drops at low temperatures. The display’s storage temperature is -30°C to 80°C. The display’s humidity range is 10% to 90% non-condensing. The display’s shock resistance is 50 G, but the COG bonding can crack under high stress. The display’s lifespan is 50,000 hours for the backlight, but the LCD itself can last 100,000 hours. The display’s ESD protection is 2 kV for the human body model. The display’s RoHS compliance is mandatory for European markets. The display’s packaging is a tray with 100 pieces. The display’s cost is $2-5 per unit in volume. The display’s application includes smartwatches, fitness trackers, and medical devices. The display’s driver IC is available in a COG package, which reduces the module size. The display’s connection to the PCB is through a flexible flat cable (FFC) with a 0.5 mm pitch. The display’s FFC has 6 pins: VCC, GND, SCLK, MOSI, CS, DC. The display’s pinout is standard, but you should check the datasheet for the exact pin assignment. The display’s datasheet includes the command set, timing diagrams, and application notes. The display’s initialization code can be written in C or Python. For Python, you can use the spidev library to send SPI commands. For example:

import spidev
import RPi.GPIO as GPIO
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000
GPIO.setmode(GPIO.BCM)
GPIO.setup(24, GPIO.OUT) # DC pin
GPIO.setup(25, GPIO.OUT) # CS pin
GPIO.output(25, GPIO.HIGH) # CS idle high
def send_command(cmd):
GPIO.output(24, GPIO.LOW) # DC low for command
GPIO.output(25, GPIO.LOW) # CS low
spi.xfer([cmd])
GPIO.output(25, GPIO.HIGH) # CS high
def send_data(data):
GPIO.output(24, GPIO.HIGH) # DC high for data
GPIO.output(25, GPIO.LOW) # CS low
spi.xfer([data])
GPIO.output(25, GPIO.HIGH) # CS high
# Initialization sequence
send_command(0xAE) # display off
send_command(0xA8) # set multiplex ratio
send_command(0x1F) # 32 rows
send_command(0xD3) # set display offset
send_command(0x00) # offset 0
send_command(0x40) # set display start line
send_command(0xA1) # set segment re-map
send_command(0xC8) # set COM scan direction
send_command(0xDA) # set COM pins
send_command(0x02) # sequential COM pins
send_command(0x81) # set contrast
send_command(0x7F) # contrast value
send_command(0xD9) # set pre-charge period
send_command(0xF1) # pre-charge value
send_command(0xDB) # set VCOMH deselect level
send_command(0x40) # VCOMH level
send_command(0xA4) # set entire display on
send_command(0xA6) # set normal display
send_command(0x2E) # deactivate scroll
send_command(0xAF) # display on
# Clear display
for page in range(4):
send_command(0xB0 + page) # set page
send_command(0x00) # set column low nibble
send_command(0x10) # set column high nibble
for col in range(128):
send_data(0x00) # clear pixel

This code initializes the display and clears it. To draw a pixel, you need to calculate the page and column, then set the write address and send the data. For example, to draw a pixel at (10, 20):

page = 20 // 8 = 2
column = 10
send_command(0xB0 + page) # set page 2
send_command(0x00 + (column & 0x0F)) # set column low nibble
send_command(0x10 + ((column >> 4) & 0x0F)) # set column high nibble
send_data(1 << (20 % 8)) # set bit 4 (since 20 % 8 = 4)

But this is tedious. Instead, you can use a frame buffer in memory and update the entire display at once. For a 128x32 display, the frame buffer is 512 bytes. You can create a bytearray of 512 bytes, set the bits for each pixel, and then write the entire buffer to the display. For example:

buffer = bytearray(512)
def set_pixel(x, y, on):
if x < 0 or x >= 128 or y < 0 or y >= 32:<