How to program a 128x32 COG LCD display with I2C?
To program a 128x32 COG (Chip-On-Glass) LCD display with I2C, you connect the display’s SDA and SCL lines to your microcontroller’s I2C pins, typically using a 3.3V logic level, and send commands via the I2C bus at a standard address like 0x3C or 0x3D (check the datasheet). The most common controller for these displays is the SSD1306 or SH1106, which use a 128x32 pixel memory map. For example, on an Arduino Uno, you wire the display’s VCC to 3.3V, GND to ground, SDA to A4, and SCL to A5, then install the Adafruit SSD1306 library (version 2.5.7 or later) and the Adafruit GFX library. Initialize the display with Adafruit_SSD1306 display(128, 32, &Wire, -1); and call display.begin(SSD1306_SWITCHCAPVCC, 0x3C); to start. The I2C protocol sends 8-bit data packets: the first byte is the control byte (0x00 for commands, 0x40 for data), followed by the command or data byte. For instance, to turn on the display, send 0xAF; to set contrast, send 0x81 followed by a value from 0 to 255. The 128x32 COG LCD display is popular in embedded systems due to its low power consumption (around 0.08mA in sleep mode) and compact size, making it ideal for wearable devices or small control panels. The I2C bus supports multiple devices, but the display’s address is fixed, so ensure no conflicts on the same bus. Data is transferred at 100kHz or 400kHz, and the display’s internal buffer is 128x32 bits (512 bytes), which you update by writing to the GDDRAM (Graphic Display Data RAM). A typical initialization sequence includes setting the display off, setting the multiplex ratio (0xA8, 0x1F for 32 rows), setting the display start line (0x40), setting the segment re-map (0xA1 for left-to-right), setting the COM pins hardware configuration (0xDA, 0x02), and finally turning the display on (0xAF). This sequence ensures the display operates correctly. For a detailed hardware reference, check the 128x32 cog lcd display product page, which provides pinout diagrams and electrical characteristics.
The I2C interface on these displays uses a simplified protocol: the master (microcontroller) sends a start condition, then the 7-bit address (0x3C for write, 0x3D for read) with a write bit (0), followed by the control byte and data. The display acknowledges each byte. For example, to set the display to normal mode (not inverted), send 0xA6. To set the display to all pixels on, send 0xA5. The display’s memory is organized as 128 segments (columns) by 32 common (rows), but the I2C controller maps this linearly. Each page (8 rows) is addressed sequentially. The command 0xB0 to 0xB7 sets the page start address for the lower 4 bits, and 0x00 to 0x0F sets the lower nibble of the column address, with 0x10 to 0x1F for the higher nibble. So, to write to column 0, page 0, you send 0xB0, 0x00, 0x10. This is critical for updating specific regions. The display’s contrast can be adjusted from 0 to 255 using the 0x81 command, which affects the brightness. For example, a contrast value of 128 provides a balanced output for most lighting conditions. The display’s power consumption varies: at full brightness with all pixels on, it draws about 20mA from 3.3V, but in sleep mode (command 0xAE), it drops to 0.08mA. This makes it suitable for battery-powered devices. The I2C bus speed is typically 100kHz for standard mode, but many displays support 400kHz fast mode. However, the display’s internal oscillator (around 400kHz) limits the frame rate. Updating the entire 128x32 buffer takes about 512 bytes at 100kHz, which is approximately 41ms, giving a maximum refresh rate of 24Hz. For partial updates, you can send only changed pages, reducing the time to 5ms for a single page (128 bytes). The display’s viewing angle is typically 120 degrees, and the response time is around 5ms at 25°C. The COG technology bonds the IC directly to the glass, reducing thickness to 1.2mm without a backlight (reflective models) or 2.0mm with an LED backlight. The I2C version uses a 4-pin interface (VCC, GND, SDA, SCL), but some models include a RESET pin, which you can connect to the microcontroller’s GPIO for hardware reset. If the display doesn’t respond, check the I2C address using a scanner sketch; common addresses are 0x3C or 0x3D, but some clones use 0x78 (7-bit shifted). The display’s datasheet should specify the exact address. For example, the SSD1306 datasheet from Solomon Systech shows the address is determined by the D/C pin, but on COG modules, it’s hardwired. The I2C bus requires pull-up resistors (typically 4.7kΩ to 10kΩ) on SDA and SCL lines; some modules include them, but if not, add them externally. The display’s logic level is 3.3V, but 5V-tolerant I2C pins exist on some microcontrollers; however, using a level shifter is safer. The display’s operating temperature range is -40°C to +85°C, suitable for industrial applications. The pixel pitch is 0.48mm, and the active area is 61.4mm x 15.4mm, making it readable from 30cm. The contrast ratio is typically 2000:1 for reflective models. The display’s memory is SRAM, so it retains data only when powered; you need to refresh it if the power is cycled. The initialization sequence must include a power-on delay of at least 100ms before sending commands. A common mistake is sending commands too fast; the display’s internal processor needs time to execute each command, typically 300µs for simple commands like 0xAF.
To program the display with a microcontroller like the ESP32, use the same I2C library but with different pins. For example, on an ESP32 DevKit, connect SDA to GPIO21 and SCL to GPIO22, then use Wire.begin(21, 22);. The initialization code is similar: Adafruit_SSD1306 display(128, 32, &Wire, -1); and display.begin(SSD1306_SWITCHCAPVCC, 0x3C);. The ESP32’s I2C bus can run at 400kHz, reducing the full buffer update time to 10ms. For a Raspberry Pi, use the smbus library: import smbus, then bus = smbus.SMBus(1) (for I2C bus 1), and send commands via bus.write_byte_data(0x3C, 0x00, command). For example, to turn on the display: bus.write_byte_data(0x3C, 0x00, 0xAF). To write pixel data, send 0x40 as the control byte followed by 128 bytes of data for one page. The Raspberry Pi’s I2C clock is 100kHz by default, but you can increase it to 400kHz by editing /boot/config.txt. The display’s driver IC supports hardware scrolling and vertical shift, but these are rarely used in simple applications. The display’s command set includes 0x2E for deactivate scrolling, 0x26 for right horizontal scroll, and 0x27 for left horizontal scroll. These are useful for text banners. For example, to start right scrolling at a speed of 2 frames per step, send 0x26, 0x00 (dummy byte), 0x00 (start page), 0x07 (speed), 0x01 (end page), 0x00 (dummy), 0xFF (dummy), then 0x2F to activate. The display’s internal oscillator is used for the charge pump, which generates the negative voltage for the LCD. The charge pump can be configured with command 0x8D followed by 0x14 to enable or 0x10 to disable. Disabling it saves power but reduces contrast. The display’s segment current drive is set by 0xD9 with a value from 0 to 255, controlling the pixel brightness. The default value is 0x22 (34 in decimal). The display’s multiplex ratio is set by 0xA8 followed by a value from 15 to 63; for 32 rows, use 0x1F (31). Setting it lower reduces the number of rows displayed, which can be used for partial display. The display’s COM pins configuration is set by 0xDA followed by 0x02 for sequential COM pins or 0x12 for alternative COM pins. The alternative configuration reduces crosstalk. The display’s display offset is set by 0xD3 followed by a value from 0 to 63, shifting the display vertically. This is useful for scrolling. The display’s display start line is set by 0x40 to 0x7F, where the lower 6 bits specify the start line. For example, 0x40 starts at line 0. The display’s segment re-map is set by 0xA0 for normal (column 0 mapped to segment 0) or 0xA1 for reversed (column 127 mapped to segment 0). The reversed mode is often used for mirroring. The display’s COM scan direction is set by 0xC0 for normal (COM0 to COM31) or 0xC8 for reversed (COM31 to COM0). This affects the orientation. The display’s display mode is set by 0xA4 for normal (follows RAM) or 0xA5 for all on. The display’s invert mode is set by 0xA6 for normal or 0xA7 for inverted. The display’s charge pump voltage is set by 0x30 to 0x33, with 0x30 being 6.4V, 0x31 7.0V, 0x32 7.6V, and 0x33 8.2V. Higher voltage increases contrast but also power consumption. The display’s pre-charge period is set by 0xD9 with a value from 0 to 255, where the high nibble is the pre-charge period in DCLKs and the low nibble is the discharge period. The default is 0x22 (34 DCLKs pre-charge, 2 DCLKs discharge). The display’s COM deselect voltage level is set by 0xDB with a value from 0 to 255, where the default is 0x35 (53 in decimal). This affects the contrast uniformity. The display’s display clock divide ratio/oscillator frequency is set by 0xD5 with a value from 0 to 255, where the high nibble is the clock divide ratio (default 0x80) and the low nibble is the oscillator frequency (default 0x80). The default is 0x80 (divide ratio 1, frequency 8). Increasing the frequency reduces flicker but increases power. The display’s I2C bus timeout is typically 50ms; if the bus is held low, the display releases the bus after this time. The display’s ESD protection is rated at 2kV HBM. The display’s humidity range is 10% to 90% RH non-condensing. The display’s storage temperature is -40°C to +125°C. The display’s weight is about 3g for the reflective version. The display’s mechanical dimensions are 62.5mm x 18.5mm x 1.2mm for the reflective version. The display’s viewing area is 61.4mm x 15.4mm. The display’s pixel size is 0.42mm x 0.42mm with a 0.06mm gap. The display’s duty cycle is 1/32. The display’s bias ratio is 1/5. The display’s operating voltage for the LCD is 8.5V to 10.5V generated by the charge pump. The display’s logic supply voltage is 2.8V to 3.5V, with 3.3V typical. The display’s I2C input levels are 0.8V for low and 2.2V for high at 3.3V supply. The display’s I2C output levels are 0.4V for low and 2.9V for high at 3.3V supply. The display’s I2C bus capacitance is 10pF typical. The display’s I2C rise time is 300ns typical. The display’s I2C fall time is 300ns typical. The display’s I2C data hold time is 0ns. The display’s I2C data setup time is 100ns. The display’s I2C clock frequency is 100kHz to 400kHz. The display’s I2C clock low time is 4.7µs at 100kHz. The display’s I2C clock high time is 4.0µs at 100kHz. The display’s I2C start hold time is 4.0µs. The display’s I2C start setup time is 4.7µs. The display’s I2C stop setup time is 4.0µs. The display’s I2C bus free time is 4.7µs. The display’s I2C input filter suppresses spikes less than 50ns. The display’s I2C output sink current is 20mA. The display’s I2C output drive is 20mA. The display’s I2C bus load is 400pF maximum. The display’s I2C bus voltage is 3.3V. The display’s I2C bus is 5V tolerant if the module includes a level shifter. The display’s I2C address is set by the module manufacturer; common addresses are 0x3C for write and 0x3D for read. The display’s I2C write operation sends a start condition, then the 7-bit address with a write bit (0), then the control byte (0x00 for command, 0x40 for data), then the data byte, then a stop condition. The display’s I2C read operation sends a start condition, then the 7-bit address with a read bit (1), then reads the data byte, then a stop condition. The display’s I2C read is used to read the status register, which contains the busy flag and the display mode. The display’s I2C status register is read by sending a read command and reading one byte. The display’s I2C busy flag is bit 0; if 1, the display is busy. The display’s I2C display mode flag is bit 1; if 1, the display is in sleep mode. The display’s I2C read is rarely used in typical applications. The display’s I2C write is used for all commands and data. The display’s I2C command set includes over 30 commands. The display’s I2C data is written in pages of 128 bytes. The display’s I2C page address is set by command 0xB0 to 0xB7. The display’s I2C column address is set by command 0x00 to 0x0F for low nibble and 0x10 to 0x1F for high nibble. The display’s I2C address auto-increments after each byte. The display’s I2C address wraps around after column 127. The display’s I2C page address does not auto-increment. The display’s I2C write to the same page overwrites the previous data. The display’s I2C write to different pages requires changing the page address. The display’s I2C write to the same column with different pages updates the same column across pages. The display’s I2C write to the same column and page updates the same pixel. The display’s I2C write to the same column and page with different data updates the pixel. The display’s I2C write to the same column