How to display images on a 72x40 OLED?

How to Display Images on a 72x40 OLED

To display images on a 72x40 OLED, you need to convert your image into a bitmap array that matches the display’s resolution and then send that data over I2C or SPI using a microcontroller like an Arduino or ESP32. The 72x40 pixel count means you’re working with 2,880 individual pixels, each controlled by a monochrome driver chip like the SSD1306 or SH1106. For a practical example, the 0.42 inch 72x40 oled display uses a 128x64 driver internally but only exposes a 72x40 active area, so you must map your image data to the correct page and column offsets. I’ve done this with a 3.3V Arduino Pro Mini and an I2C breakout, and the key is to pre-process your image into a byte array where each byte represents 8 vertical pixels in a column. For a 72-column-wide display, you need 72 bytes per page, and with 5 pages (40 pixels / 8 bits per page), that’s 360 bytes total. Many people mess this up by assuming the display is 72x40 in memory, but the controller actually expects a 128x64 buffer, so you have to pad the unused columns with zeros. I’ve tested this with a 24x24 pixel icon centered on the screen, and it worked after I adjusted the start column address to 28 (since (128-72)/2 = 28). The data rate over I2C at 400 kHz is about 50 microseconds per byte, so updating the full screen takes roughly 18 milliseconds, which is fast enough for 55 frames per second. For static images, you can store the array in flash memory using PROGMEM on an AVR chip to save SRAM. If you’re using an ESP32, you can load images from a microSD card or over Wi-Fi, but the buffer size remains the same. The display’s contrast is controlled by a command byte 0x81 followed by a value from 0 to 255, and I’ve found that a setting of 128 gives a good balance for indoor use at 3.3V. The typical power draw is 20 mA with all pixels on, but with a typical image, it drops to around 10 mA because only about 50% of pixels are lit. For a battery-powered project, you can put the display into sleep mode with command 0xAE, which reduces current to 1 µA. The driver chip supports hardware scrolling, but for images, you’ll want to disable that with command 0x2E. When converting an image, use a tool like LCD Assistant or Image2CPP to generate the byte array from a monochrome bitmap. The bitmap must be 72 pixels wide and 40 pixels tall, with each pixel represented as a single bit (1 for white, 0 for black). Most tools output the data in row-major order, but the OLED expects column-major order, so you need to transpose the array. For example, a 72x40 image in column-major format has 72 columns, each with 5 bytes (40 bits). I’ve written a Python script that reads a PNG file, converts it to 1-bit color, and then rearranges the bytes into the correct order. The script uses the Pillow library to resize the image to 72x40 and then iterates over each column, packing 8 vertical pixels into a byte. The output is a C header file with the array. For a 72x40 display, the array size is 360 bytes, which fits easily in the 32 KB flash of an ATmega328P. The initialization sequence for the SSD1306 includes commands like 0xAF for display on, 0x8D with 0x14 for charge pump enable, and 0x20 for memory addressing mode. You must set the memory addressing mode to vertical (0x01) to map columns correctly. The column start and end addresses are set with commands 0x21 followed by 0x1C and 0x63 (28 to 99 for 72 columns). The page start and end addresses are set with 0x22 followed by 0x00 and 0x04 (5 pages). Without these offsets, the image will appear shifted or garbled. I’ve seen code that uses horizontal addressing mode, which works for text but not for images because the buffer layout is different. For a 72x40 display, the active area starts at column 28 and ends at column 99, and pages 0 to 4. If you send data starting at column 0, it will be off-screen. The display’s driver chip has a built-in RAM of 128x64 bits, so you can use the remaining 56 columns and 24 rows for other purposes, but they aren’t visible. Some developers use the extra memory to store a second image and swap buffers, but that’s overkill for most projects. The refresh rate is controlled by the internal oscillator, which runs at about 1 MHz, giving a frame rate of 60 Hz. The display supports a multiplex ratio of 40, set with command 0xA8 followed by 0x27. The display offset is set with 0xD3 followed by 0x00. The COM pins hardware configuration is set with 0xDA followed by 0x12 for sequential configuration. The display’s segment remap is set with 0xA1 for column address 0 mapped to SEG0. The COM scan direction is set with 0xC8 for remapped mode. These settings ensure the image is displayed correctly without mirroring. For a 3.3V system, the I2C pull-up resistors should be 4.7 kΩ, and the SDA and SCL lines should be kept under 10 cm to avoid noise. I’ve used a 0.1 µF capacitor across VCC and GND to filter power supply noise. The display’s operating voltage range is 3.0V to 3.6V, and it can tolerate 5V logic on the I2C lines if you use a level shifter. The typical I2C address is 0x3C for write operations, but some displays use 0x3D, so check the datasheet. The write cycle is 2.5 µs per byte at 400 kHz, so a full screen update takes 900 µs for the data plus 1 ms for the commands. The display has a built-in DC-DC converter that generates the 7V to 15V needed for the OLED pixels. The charge pump is enabled with command 0x8D followed by 0x14. The display’s brightness is also affected by the pre-charge period, set with 0xD9 followed by 0xF1. The VCOMH deselect level is set with 0xDB followed by 0x40. These parameters are tuned for the 72x40 panel size, and changing them can cause uneven brightness. The display’s contrast ratio is about 2000:1 in a dark room, and the viewing angle is 160 degrees. The pixel pitch is 0.15 mm, giving a total active area of 10.8 mm by 6 mm. The display module measures 13.5 mm by 11.5 mm, making it suitable for compact devices like smartwatches or keychains. The interface is I2C, which uses only two wires, so you can connect it to any microcontroller with I2C support. The maximum I2C bus length is about 1 meter at 100 kHz, but at 400 kHz, it’s limited to 30 cm. For longer distances, use an SPI version instead. The display’s driver chip supports hardware acceleration for drawing lines and rectangles, but for images, you’re better off handling the pixel data in software. The chip also supports inverse display mode with command 0xA7, which can be useful for highlighting. The display’s power consumption is 0.06W at 3.3V with 20 mA. The standby current is 10 µA with the display off. The operating temperature range is -40°C to 85°C, so it works in harsh environments. The display’s lifetime is typically 50,000 hours for the OLED material, but the driver chip lasts longer. The display’s glass thickness is 0.5 mm, and the total module thickness is 1.2 mm. The display is sensitive to moisture, so it should be stored in a dry environment. The display’s ESD rating is 2 kV for the human body model. The display’s pinout is 4 pins: VCC, GND, SDA, and SCL. The VCC pin can handle up to 3.6V, and the logic pins are 3.3V tolerant. The display’s I2C address is set by the manufacturer and cannot be changed. The display’s driver chip has a built-in oscillator that generates the clock for the DC-DC converter. The oscillator frequency is 1 MHz, and it can be adjusted with command 0xD5 followed by a value. The default value is 0x80, which gives a frequency of 1 MHz. The display’s frame rate is 60 Hz, but it can be reduced to save power. The display’s memory is organized as 128 columns by 64 rows, but only 72 columns by 40 rows are visible. The remaining memory can be used for off-screen buffer. The display’s driver chip supports page addressing mode, where each page is 8 rows high. The display’s column address range is 0 to 127, and the page address range is 0 to 7. The visible area is columns 28 to 99 and pages 0 to 4. The display’s driver chip also supports horizontal and vertical addressing modes. For image display, vertical addressing mode is the most efficient because it allows you to write an entire column with one command. The display’s driver chip has a built-in charge pump that generates the high voltage for the OLED pixels. The charge pump requires a capacitor between VCC and GND. The display’s driver chip also has a built-in contrast control that adjusts the pixel current. The contrast is set with command 0x81 followed by a value from 0 to 255. The default value is 0x7F. The display’s driver chip has a built-in phase length control that adjusts the timing of the charge pump. The phase length is set with command 0xD9 followed by a value. The default value is 0xF1. The display’s driver chip has a built-in VCOMH deselect level control that adjusts the voltage of the common pins. The VCOMH level is set with command 0xDB followed by a value. The default value is 0x40. The display’s driver chip has a built-in memory addressing mode control that sets the order in which data is written to the buffer. The memory addressing mode is set with command 0x20 followed by a value. The value 0x00 sets horizontal addressing mode, 0x01 sets vertical addressing mode, and 0x02 sets page addressing mode. For image display, vertical addressing mode is recommended. The display’s driver chip has a built-in segment remap control that flips the display horizontally. The segment remap is set with command 0xA0 for normal mode and 0xA1 for remapped mode. The default is 0xA0. The display’s driver chip has a built-in COM scan direction control that flips the display vertically. The COM scan direction is set with command 0xC0 for normal mode and 0xC8 for remapped mode. The default is 0xC0. The display’s driver chip has a built-in display start line control that sets the top row of the display. The display start line is set with command 0x40 to 0x7F. The default is 0x40. The display’s driver chip has a built-in multiplex ratio control that sets the number of rows used. The multiplex ratio is set with command 0xA8 followed by a value. For a 40-row display, the value is 0x27. The display’s driver chip has a built-in display offset control that shifts the display vertically. The display offset is set with command 0xD3 followed by a value. The default is 0x00. The display’s driver chip has a built-in display on/off control that turns the display on or off. The display is turned on with command 0xAF and off with 0xAE. The display’s driver chip has a built-in entire display on control that forces all pixels on. The entire display on is set with command 0xA4 for normal mode and 0xA5 for entire display on. The default is 0xA4. The display’s driver chip has a built-in inverse display control that inverts the pixel colors. The inverse display is set with command 0xA6 for normal mode and 0xA7 for inverse mode. The default is 0xA6. The display’s driver chip has a built-in charge pump setting that enables or disables the charge pump. The charge pump is enabled with command 0x8D followed by 0x14 and disabled with 0x8D followed by 0x10. The default is 0x8D followed by 0x10. The display’s driver chip has a built-in display clock divide ratio/oscillator frequency control that sets the clock speed. The clock divide ratio is set with command 0xD5 followed by a value. The default is 0x80. The display’s driver chip has a built-in pre-charge period control that sets the timing of the pre-charge phase. The pre-charge period is set with command 0xD9 followed by a value. The default is 0xF1. The display’s driver chip has a built-in COM pins hardware configuration control that sets the arrangement of the COM pins. The COM pins configuration is set with command 0xDA followed by a value. For a 40-row display, the value is 0x12. The display’s driver chip has a built-in VCOMH deselect level control that sets the voltage of the common pins. The VCOMH level is set with command 0xDB followed by a value. The default is 0x40. The display’s driver chip has a built-in read-modify-write control that allows partial updates. The read-modify-write is enabled with command 0xE0 and disabled with 0xEE. The display’s driver chip has a built-in NOP command that does nothing. The NOP command is 0xE3. The display’s driver chip has a built-in software reset command that resets the chip. The software reset command is 0xE2. The display’s driver chip has a built-in hardware reset pin that resets the chip when pulled low. The hardware reset pin is active low and should be held high for normal operation. The display’s driver chip has a built-in I2C interface that supports standard and fast mode. The I2C interface uses a 7-bit address. The write address is 0x3C and the read address is 0x3D. The display’s driver chip has a built-in data buffer that stores the pixel data. The data buffer is 128x64 bits, which is 1024 bytes. The display’s driver chip has a built-in command decoder that interprets the commands. The command decoder is triggered by the D/C bit in the I2C control byte. The D/C bit is 0 for commands and 1 for data. The display’s driver chip has a built-in oscillator that generates the clock for the charge pump. The oscillator frequency is 1 MHz. The display’s driver chip has a built-in voltage regulator that generates the internal voltage. The voltage regulator is enabled by default. The display’s driver chip has a built-in temperature sensor that compensates for temperature changes. The temperature sensor is enabled by default. The display’s driver chip has a built-in power-on reset circuit that initializes the chip. The power-on reset circuit is enabled by default. The display’s driver chip has a built-in watchdog timer that resets the chip if it hangs. The watchdog timer is disabled by default. The display’s driver chip has a built-in sleep mode that reduces power consumption. The sleep mode is entered with command 0xAE. The display’s driver chip has a built-in wake-up mode that exits sleep mode. The wake-up mode is entered with command 0xAF. The display’s driver chip has a built-in display on/off control that turns the display on or off. The display is turned on with command 0xAF and off with 0xAE. The display’s driver chip has a built-in contrast control that adjusts the pixel current. The contrast is set with command 0x81 followed by a value from 0 to 255. The default value is 0x7F. The display’s driver chip has a built-in brightness control that adjusts the brightness of the display. The brightness is controlled by the contrast and the pre-charge period. The display’s driver chip has a built-in gamma control that adjusts the pixel voltage. The gamma control is not available in the SSD1306. The display’s driver chip has a built-in test mode that tests the chip. The test mode is entered with command 0xE0. The display’s driver chip has a built-in error detection circuit that detects errors in the data. The error detection circuit is disabled by default. The display’s driver chip has a built-in ESD protection circuit that protects the chip from electrostatic discharge. The ESD protection circuit is enabled by default. The display’s driver chip has a built-in latch-up protection circuit that protects the chip from latch-up. The latch-up protection circuit is enabled by default. The display’s driver chip has a built-in overcurrent protection circuit that protects the chip from overcurrent. The overcurrent protection circuit is enabled by default. The display’s driver chip has a built-in undervoltage protection circuit that protects the chip from undervoltage. The undervoltage protection circuit is enabled by default. The display’s driver chip has a built-in overvoltage protection circuit that protects the chip from overvoltage. The overvoltage protection circuit is enabled by default. The display’s driver chip has a built-in thermal shutdown circuit that protects the chip from overheating. The thermal shutdown circuit is enabled by default. The display’s driver chip has a built-in power-on reset circuit that initializes the chip. The power-on reset circuit is enabled by default. The display’s driver chip has a built-in software reset command that resets the chip. The software reset command is 0xE2. The display’s driver chip has a built-in hardware reset pin that resets