How to use a 0.66 inch OLED with a Pico?
How to Use a 0.66 Inch OLED with a Pico
To get a 0.66 inch OLED display working with a Raspberry Pi Pico, you need to wire it up via SPI, install the right MicroPython libraries, and write code to drive the 64x64 pixel matrix. This specific OLED, which uses the SSD1306 driver chip but in a smaller 64x64 resolution instead of the common 128x64, runs at 3.3V logic and draws around 20mA during operation. The Pico’s GPIO pins are 3.3V tolerant, so no level shifting is required. The OLED module typically has seven pins: GND, VCC, D0 (SCLK), D1 (MOSI), RES, DC, and CS. You connect GND to Pico ground, VCC to 3.3V out, D0 to GP2 (SCLK), D1 to GP3 (MOSI), RES to GP4, DC to GP5, and CS to GP6. That’s the hardware side—straightforward, no soldering needed if you use a breadboard and jumper wires.
The display resolution is 64x64 pixels, which is a square format, not the more common rectangular 128x64. This means each pixel is individually addressable, but the total pixel count is 4,096. The SSD1306 controller inside handles the RAM buffer internally, requiring about 512 bytes of SRAM (64 columns * 64 rows / 8 bits per byte). For the Pico, with its 264KB of RAM, that’s negligible. The SPI clock speed can go up to 10MHz without issues, but for stability, I’d start at 1MHz and ramp up. The default I2C version of the SSD1306 is more common, but this SPI variant gives you faster refresh rates—up to 60fps for simple graphics, though real-world performance with MicroPython might hit 30fps due to interpreter overhead.
For the software, you need the MicroPython firmware on the Pico. Download the latest .uf2 file from the Raspberry Pi website, hold the BOOTSEL button on the Pico while plugging it into USB, and drag the file onto the RPI-RP2 drive. Then, write a script using the machine and framebuf libraries. The SSD1306 driver for SPI is not built into MicroPython by default, so you’ll need to grab a custom version that supports 64x64 resolution. The standard Adafruit SSD1306 library assumes 128x64, so you have to modify the page addressing. Here’s a snippet: initialize SPI with spi = machine.SPI(1, baudrate=1000000, sck=machine.Pin(2), mosi=machine.Pin(3)), then create the display object with display = SSD1306_SPI(64, 64, spi, machine.Pin(4), machine.Pin(5), machine.Pin(6)). The framebuf module gives you methods like text(), pixel(), and line() to draw on the buffer, then call display.show() to push the buffer to the OLED.
One key detail: the SSD1306’s internal memory is organized in pages of 8 rows. For a 64x64 display, you have 8 pages (64 rows / 8). Each page holds 64 bytes (one byte per column). So the total buffer size is 512 bytes. If you use the standard 128x64 driver, it will try to send 1024 bytes, which corrupts the display. You must adjust the write_cmd and write_data functions in the driver to handle the correct column start and end registers. The command sequence for a 64x64 OLED is: set column start at 0, column end at 63, page start at 0, page end at 7. This is done via the 0x21 (column address) and 0x22 (page address) commands. Without this, you’ll get ghosting or missing pixels.
Power consumption is another factor. The 0.66 inch 64x64 oled display draws about 0.5mA in sleep mode and 15-25mA when active, depending on how many pixels are lit. The Pico itself draws around 25mA idle, so total system power is under 50mA. This makes it suitable for battery-powered projects. You can put the OLED to sleep with the 0xAE command (display off) and wake it with 0xAF. To save power, set the contrast via 0x81 followed by a value from 0 to 255. Lower contrast reduces current draw by about 10-15%.
For real-world use, I’ve tested this setup with a temperature sensor (DHT22) and displayed readings. The 64x64 resolution is tight for text—you can fit about 4 lines of 8 characters using a 5x7 font, but that’s with no spacing. For better readability, use a 4x6 font, which gives you 8 lines of 16 characters. The framebuf library supports custom fonts, but you need to convert them to byte arrays. For graphics, you can draw a 64x64 bitmap, but it’s a 512-byte array. Pre-calculate it in Python or use a tool like img2bytearray.
Timing is critical. The SPI communication uses a 4-wire interface: SCLK, MOSI, DC, and CS. The RES pin is used for hardware reset—pull it low for 10ms, then high. The DC pin tells the OLED whether the incoming data is a command (low) or data (high). The CS pin selects the chip; keep it low during transactions. The SSD1306 expects data in MSB-first order, so the Pico’s SPI default is fine. The maximum SPI clock for the SSD1306 is 10MHz, but the Pico can go up to 133MHz on the SPI bus; however, the OLED won’t respond reliably above 10MHz. Stick to 1-4MHz for stability.
If you’re using the 0.66 inch 64x64 oled display from DisplayModule, the pinout is standard: GND, VCC, D0, D1, RES, DC, CS. Some modules also include a BS0/BS1 pin for interface selection—set BS0 to 0 and BS1 to 1 for SPI mode. Check the datasheet for your specific module; some have pull-up resistors on CS and DC, which can affect GPIO configuration. The Pico’s internal pull-ups are weak (50k ohms), so external 10k resistors on CS and DC are fine if you want to avoid floating pins.
For debugging, common issues include no display output. First, check the wiring: GND and VCC are the most common mistakes. Second, verify the SPI pins: the Pico has two SPI peripherals. SPI0 uses GP16-19, and SPI1 uses GP8-11. If you use the wrong pins, the display won’t respond. Third, ensure the driver is correct for 64x64. If you see random pixels, the column/page addressing is off. Use a logic analyzer to check the SPI signals—the command bytes should be 0x21, 0x00, 0x3F for columns and 0x22, 0x00, 0x07 for pages. The data bytes should be the buffer content.
Performance optimization: MicroPython’s framebuf is slow for full-screen updates. For animations, update only changed regions. Use the display.poweron() and display.poweroff() methods if available, or send the 0xAF/0xAE commands directly. The OLED’s refresh rate is limited by the internal oscillator, which runs at about 400kHz. The frame rate is roughly 60Hz for 128x64, but for 64x64, it’s higher because fewer pixels are scanned. In practice, the SPI bus speed is the bottleneck. At 1MHz, a full 512-byte buffer takes about 4ms to transfer, so you can do 250 updates per second theoretically, but MicroPython overhead reduces that to 50-100 updates per second.
Another angle: the 0.66 inch OLED uses a monochrome white or blue pixel matrix, depending on the model. The white version has a higher contrast ratio (2000:1) and a wider viewing angle (160 degrees). The blue version is slightly dimmer but uses less power. The operating temperature range is -40 to 85 degrees Celsius, making it suitable for outdoor projects. The OLED’s lifetime is rated at 50,000 hours to half brightness, which is typical for passive matrix OLEDs.
For advanced use, you can implement partial updates. The SSD1306 supports horizontal and vertical scrolling via commands 0x26 and 0x27. This is useful for text tickers without CPU overhead. The scrolling region is set by the 0x2A and 0x2B commands. For example, to scroll the entire display, set the start page to 0, end page to 7, and the scroll speed in frames. The speed is controlled by the 0x29 command with a value from 0 to 7. This is hardware-accelerated and doesn’t require buffer updates.
If you’re using C or C++ on the Pico, the SDK provides hardware SPI access. The Pico’s SPI can be configured with DMA for zero-CPU-overhead transfers. The buffer is stored in the Pico’s SRAM, and you can use a timer to trigger updates at fixed intervals. The SSD1306’s command set is the same, but you’ll write a driver that directly manipulates the SPI registers. The Pico’s PIO (Programmable I/O) can also be used to bit-bang SPI if you need to free up the main CPU. This is overkill for a 64x64 display, but it’s an option for complex projects.
Common pitfalls: voltage mismatch. The Pico’s 3.3V output is fine, but some OLED modules have a built-in 3.3V regulator and can accept 5V input. Check the datasheet—if VCC is labeled 5V, you can power it from the Pico’s VBUS pin (5V from USB). But the logic pins are still 3.3V, so don’t connect 5V to the Pico GPIOs. Also, the OLED’s RES pin is active low. If you don’t reset it properly, the display might show garbage. A hardware reset sequence: set RES low, wait 10ms, set RES high, wait 10ms, then send the initialization commands.
Initialization commands for the SSD1306 64x64: 0xAE (display off), 0xD5 (set display clock divide ratio/oscillator frequency) with value 0x80, 0xA8 (set multiplex ratio) with value 0x3F (64 rows), 0xD3 (set display offset) with value 0x00, 0x40 (set display start line to 0), 0x8D (charge pump setting) with value 0x14 (enable charge pump), 0x20 (set memory addressing mode) with value 0x00 (horizontal), 0xA1 (set segment re-map to column 127 mapped to SEG0), 0xC8 (set COM output scan direction to remapped mode), 0xDA (set COM pins hardware configuration) with value 0x12, 0x81 (set contrast) with value 0xCF, 0xD9 (set pre-charge period) with value 0xF1, 0xDB (set VCOMH deselect level) with value 0x40, 0xA4 (set entire display on to follow RAM content), 0xA6 (set normal display), 0x2E (deactivate scroll), 0xAF (display on). This sequence is standard for 64x64; the multiplex ratio of 0x3F is critical—using 0x3F for 128x64 would cause issues.
For the Pico’s pin assignment, I recommend using GP2-6 because they are on the same side of the board and easily accessible. If you need to use other pins, ensure they are not used by the USB or debug UART. GP0 and GP1 are used for UART0, GP14 and GP15 for UART1, so avoid those if you’re using serial. The SPI pins can be remapped using the Pico’s pin mux, but the default SPI0 on GP16-19 works too. Just change the SPI initialization accordingly.
In terms of display quality, the 0.66 inch OLED has a pixel pitch of about 0.21mm, giving a PPI (pixels per inch) of roughly 120. This is readable for small text but not for fine details. The viewing angle is 160 degrees, so it’s visible from almost any angle. The brightness is typically 100 cd/m² for white OLEDs, which is dimmer than a phone screen but fine for indoor use. For outdoor use, you’ll need a sunshade or higher contrast settings.
One more thing: the SPI interface on the Pico is 3.3V, but the OLED’s logic threshold is typically 0.7*VCC for a high and 0.3*VCC for a low. At 3.3V, the high threshold is 2.31V, which the Pico easily meets. The low threshold is 0.99V, also fine. So no level shifting needed. However, if you use long wires (over 20cm), signal integrity might degrade. Keep wires short, under 10cm, and use twisted pairs for SCLK and MOSI if possible.
For the power supply, the Pico can source up to 300mA from the 3.3V pin, so the OLED’s 20mA is safe. But if you’re powering other peripherals, check the total draw. The Pico’s 3.3V regulator is rated for 300mA, but it can get hot if you draw near that. Use a separate 3.3V regulator if you have multiple power-hungry devices.
To test the display, write a simple script that fills the screen with a pattern. For example, use display.fill(1) to turn all pixels white, then display.show(). If you see a solid white square, the wiring and driver are correct. Then try display.text('Hello', 0, 0, 1) to print text. The font in framebuf is 8x8 pixels, so a 64x64 display can show 8 characters per line and 8 lines, but the characters are large. For smaller fonts, you need to implement a custom bitmap font.
If you’re using the I2C version of the 0.66 inch OLED, the pinout is different: GND, VCC, SCL, SDA, and sometimes RES. The I2C address is usually 0x3C or 0x3D. The Pico’s I2C pins are GP4 (SDA) and GP5 (SCL) for I2C0, or GP6 and GP7 for I2C1. The I2C speed is 400kHz max, which is slower than SPI. For a 64x64 display, I2C is fine for static content, but for animations, SPI is better. The I2C driver also needs the 64x64 buffer size adjustment.
For the 0.66 inch 64x64 oled display from DisplayModule, the module includes a built-in capacitor for the charge pump, so you don’t need external components. The PCB is 18x18mm, making it compact for embedding in enclosures. The connector is a 7-pin header with 2.54mm pitch, compatible with standard breadboards. The display’s thickness is 1.2mm without the PCB, and the total module thickness is about 3mm. This is thin enough for wearable projects.
In terms of code optimization, use micropython.opt_level(3) to reduce bytecode size, and pre-calculate bitmaps as byte arrays. For example, a 64x64 bitmap of a circle can be stored in a 512-byte array and loaded with display.blit_buffer(buffer, 0, 0, 64, 64). The blit_buffer method is faster than drawing pixel by pixel. The <