How to use a 0.96 inch OLED with an LPC1768?

By admin

How to Use a 0.96 Inch OLED with an LPC1768

To directly answer your question: you can use a 0.96 inch 128x64 i2c oled display with an LPC1768 by connecting four wires—VCC, GND, SCL, and SDA—to the corresponding pins on the microcontroller, then writing C code that initializes the display via the I2C bus and sends pixel data to the SSD1306 driver. The LPC1768, based on the ARM Cortex-M3 core running at up to 100 MHz, handles this easily because its I2C peripheral supports clock speeds up to 400 kHz (fast mode) and even 1 MHz (fast mode plus) with proper configuration. For example, the SSD1306 controller inside the OLED typically operates at a default I2C address of 0x3C or 0x3D, depending on the SA0 pin level. You’ll need to set the LPC1768’s I2C clock register (I2SCLH and I2SCLL) to generate a 400 kHz SCL signal, which for a 100 MHz system clock means setting both registers to 125 (100 MHz / (2 * 400 kHz) = 125). This ensures reliable data transfer for the 128x64 pixel array, which requires 1024 bytes of frame buffer (128 columns * 64 rows / 8 bits per page).

Let’s break down the hardware connection first. The 0.96 inch 128x64 i2c oled display typically has a 4-pin header: VCC (3.3V or 5V), GND, SCL (clock), and SDA (data). The LPC1768 operates at 3.3V logic, so you must power the OLED from the LPC1768’s 3.3V output pin, not the 5V pin, to avoid damaging the SSD1306 chip. The maximum current draw for the OLED is around 20 mA during full brightness, which the LPC1768’s 3.3V regulator can handle (it provides up to 300 mA on most boards like the mbed LPC1768). Connect SCL to the LPC1768’s P0.1 (SCL1) and SDA to P0.0 (SDA1), which are the default I2C1 pins. If you’re using the mbed LPC1768, these pins are labeled on the DIP socket. Alternatively, you can use I2C0 on P0.27 (SDA0) and P0.28 (SCL0), but I2C1 is more common for external displays because it’s less likely to conflict with onboard peripherals. Use 4.7 kΩ pull-up resistors on both SCL and SDA lines if your display module doesn’t include them—most breakout boards do, but verify with a multimeter. The pull-up resistors are critical for I2C communication; without them, the bus will stay low and the display won’t respond.

Now, let’s talk about the I2C initialization on the LPC1768. The LPC1768 has two I2C peripherals, I2C0 and I2C1, each with a dedicated register set. For I2C1, you need to enable the peripheral clock in the PCONP register (bit 5 for I2C1). Then set the PINSEL registers to configure P0.0 and P0.1 as SDA1 and SCL1: PINSEL0 bit 0:1 = 0b10 (function 2 for P0.0) and PINSEL0 bit 2:3 = 0b10 (function 2 for P0.1). Set the I2C clock rate by writing to I2SCLH and I2SCLL. For a 100 MHz system clock and 400 kHz SCL, both registers get 125. The formula is: I2SCLH = I2SCLL = (PCLK / (2 * SCL frequency)) - 1, but for LPC1768, the peripheral clock is the same as the system clock (100 MHz) unless you change the divider. So 100,000,000 / (2 * 400,000) = 125. If you want a slower 100 kHz, set both to 500. The I2C controller then handles START, STOP, and data byte transmission automatically. You enable the I2C interface by setting the I2EN bit in the I2CONSET register. After that, the I2C state machine guides you through the protocol: send START, send device address (0x3C or 0x3D) with write bit (0), wait for ACK, send command byte, then data bytes, and finally STOP. The SSD1306 expects commands to be sent with the control byte 0x00 (Co = 0, D/C# = 0) and data with 0x40 (Co = 0, D/C# = 1).

For the SSD1306 initialization sequence, you must send a specific set of commands to configure the display. The typical sequence for a 128x64 OLED with I2C includes: 0xAE (display off), 0xD5 (set display clock divide ratio/oscillator frequency), 0x80 (default ratio), 0xA8 (set multiplex ratio), 0x3F (64 rows), 0xD3 (set display offset), 0x00 (no offset), 0x40 (set start line to 0), 0x8D (enable charge pump), 0x14 (enable charge pump for 3.3V), 0x20 (set memory addressing mode), 0x00 (horizontal mode), 0xA1 (set segment remap to column 127), 0xC8 (set COM output scan direction to remapped mode), 0xDA (set COM pins hardware configuration), 0x12 (alternative pin configuration), 0x81 (set contrast), 0xCF (contrast value, about 207), 0xD9 (set pre-charge period), 0xF1 (phase 1: 15, phase 2: 1), 0xDB (set VCOMH deselect level), 0x40 (0.77 x VCC), 0xA4 (display on resume), 0xA6 (normal display, not inverted), 0x2E (deactivate scroll), 0xAF (display on). Each command is sent as a single byte preceded by the control byte 0x00. After sending 0xAF, the display turns on and shows whatever is in the GDDRAM (which defaults to random data). You can clear it by writing 0x00 to all 1024 bytes.

Writing pixel data to the OLED requires understanding the SSD1306’s memory layout. The 128x64 display is organized into 8 pages (page 0 to page 7), each page being 128 columns by 8 rows. So page 0 covers rows 0-7, page 1 covers rows 8-15, and so on. To write a pixel at (x, y), you calculate the page number as y / 8, the bit position within that page as y % 8, and the column as x. You then set the column address range (0x21 command) and page address range (0x22 command) to target the specific area. For example, to write a single pixel at (10, 20), send: 0x21 (set column address), 0x0A (start column 10), 0x0A (end column 10), 0x22 (set page address), 0x02 (page 2, since 20/8=2), 0x02 (end page 2), then 0x40 (data control byte), then the data byte with bit 4 set (20 % 8 = 4). This is inefficient for large graphics, so you typically allocate a 1024-byte frame buffer in the LPC1768’s RAM (which has 64 KB total, so 1 KB is trivial). You update the buffer in RAM, then send the entire buffer to the display by setting column range 0 to 127 and page range 0 to 7, then sending 1024 bytes of data. At 400 kHz I2C, transferring 1024 bytes takes about 1024 * 9 bits (8 data + 1 ACK) / 400,000 = 23 ms, which is fast enough for 30 fps animations. The LPC1768’s DMA can offload this, but for simplicity, polling the I2C status register works fine.

Let’s look at a concrete code example for the LPC1768 using the mbed framework or bare-metal C. I’ll assume you’re using the mbed LPC1768 board, which simplifies I2C with the mbed library. In mbed, you instantiate an I2C object: I2C i2c(p9, p10) for SDA and SCL (p9 is P0.0, p10 is P0.1 on mbed). Then you write to the display: i2c.write(0x3C << 1, command_array, length); but note that mbed’s write expects the 7-bit address left-shifted by 1. So for address 0x3C, you pass 0x78. The command array includes the control byte (0x00 for commands) followed by the command bytes. For data, you use 0x40 as the first byte. A typical init function sends a sequence like:

char init_cmds[] = {0x00, 0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0x8D, 0x14, 0x20, 0x00, 0xA1, 0xC8, 0xDA, 0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6, 0x2E, 0xAF};
i2c.write(0x78, init_cmds, 27);

This sends 27 bytes: the first 0x00 tells the SSD1306 that the following bytes are commands. Then you clear the display by sending 1025 bytes: 0x40 followed by 1024 bytes of 0x00. For a bitmap, you send 0x40 then the 1024 bytes of pixel data. The mbed library handles the I2C protocol, but you can also implement it manually with the LPC1768’s I2C registers for more control. For example, a bare-metal I2C write function checks the I2C status register (I2STAT) after each byte to ensure ACK. The status codes are documented in the LPC1768 user manual (UM10360). For a master transmitter, the states are: 0x08 (START sent), 0x18 (address + write sent, ACK received), 0x28 (data byte sent, ACK received), and 0x20 (address + write sent, NACK). You loop until the state machine reaches 0x28 for each data byte, then send STOP by setting the STO bit in I2CONSET.

Performance-wise, the LPC1768 can drive the OLED at 60+ fps if you use DMA for I2C transfers. The LPC1768’s GPDMA controller can transfer data from a memory buffer to the I2C1 data register (I2DAT) without CPU intervention. You set up a DMA channel with source address as your frame buffer, destination as the I2C1 data register (0x4005C008), and transfer size of 1024 bytes. The DMA triggers on the I2C’s data request signal. This reduces CPU load to near zero during display updates, leaving the Cortex-M3 free for other tasks like sensor reading or motor control. The DMA controller supports up to 8 channels, each with configurable burst size and priority. For a 400 kHz I2C, a single DMA transfer of 1024 bytes takes about 23 ms, so you can achieve 43 fps theoretically. In practice, you’ll hit around 30 fps due to overhead from setting up the DMA and the I2C start/stop conditions.

Power consumption is another factor. The OLED itself draws about 20 mA at full brightness, but the LPC1768 can reduce this by putting the display into sleep mode via the 0xAE command (display off). You can also adjust the contrast with the 0x81 command to lower power. For example, setting contrast to 0x01 reduces current to around 5 mA, but the display becomes very dim. The LPC1768’s power consumption during I2C operation is about 50 mA at 100 MHz, so the total system draw is around 70 mA. If you’re battery-powered, consider using the LPC1768’s deep sleep mode (power-down) and waking via an external interrupt. The OLED retains its GDDRAM content when powered off if you keep VCC applied, but the pixel data is lost if you remove power entirely. For persistent displays, you’d need to reinitialize and redraw after wake-up.

Common issues and troubleshooting: If the display shows nothing, check the I2C address. Use an I2C scanner to detect the device—the LPC1768 can scan addresses 0x01 to 0x7F by sending a START and address, then checking for ACK. The SSD1306 often uses 0x3C, but some modules have a jumper to change it to 0x3D. Also, verify the pull-up resistors; without them, the SCL and SDA lines will float. I’ve seen cases where the display works at 100 kHz but fails at 400 kHz due to capacitive loading on long wires—keep the I2C traces under 10 cm. If the display shows garbled pixels, the initialization sequence might be missing a command. The SSD1306 datasheet specifies that the charge pump must be enabled (0x8D, 0x14) for 3.3V operation; if you skip this, the display will be blank. Another gotcha: the LPC1768’s I2C1 pins (P0.0 and P0.1) are also used for UART1 on some boards, so ensure you don’t have conflicting peripherals enabled. On the mbed LPC1768, these pins are dedicated to I2C1 by default.

For advanced use, you can implement partial screen updates by only sending changed pages. For example, if you’re updating a text cursor, calculate the page and column range, then send only those bytes. The SSD1306 supports horizontal and vertical scrolling, which you can activate with commands like 0x26 (continuous horizontal scroll) and 0x27 (vertical and horizontal scroll). The LPC1768 can set up scrolling by writing to the scroll registers, but the scroll effect is hardware-driven, so no CPU overhead once started. To stop scrolling, send 0x2E. The scroll speed is configurable via the 0xD5 command (divide ratio). For a slow scroll, set the divide ratio to 0xF0 (higher value = slower).

Data integrity is crucial for I2C communication. The LPC1768’s I2C controller includes a timeout feature in the I2CONCLR register to prevent bus lock-ups. If the slave holds the clock low (clock stretching), the master waits indefinitely. The SSD1306 can stretch the clock for up to 50 µs during command processing, but the LPC1768’s default timeout is disabled. You can enable it by setting the I2TIMEOUT register to a value like 1000 (1 ms at 100 MHz). This ensures that if the display hangs, the bus recovers. Also, the LPC1768 supports repeated START conditions, which are useful for reading from the OLED (though the SSD1306 doesn’t support read-back of GDDRAM in I2C mode—only write). For reading the status register, you’d use a repeated START to switch from write to read mode, but the SSD1306’s read capability is limited to the status register (0x00 for idle, 0x01 for busy).

Environmental factors: The OLED operates from -40°C to +85°C, while the LPC1768 is rated for -40°C to +85°C as well, so they’re compatible for industrial applications. The 0.96 inch OLED’s viewing angle is >160°, and its contrast ratio is 2000:1, making it readable in direct sunlight if you set the brightness high. The LPC1768’s GPIOs are 5V-tolerant, but the I2C pins are not—they’re 3.3V only, so never connect a 5V OLED directly. The 0.96 inch 128x64 i2c oled display I linked uses a 3.3V regulator on board, so it’s safe. If you’re using a raw SSD1306 module without a regulator, feed it 3.3V from the LPC1768’s 3.3V rail.

For debugging, use an oscilloscope to probe the SCL and SDA lines. The I2C protocol expects a clean square wave on SCL, and data changes only when SCL is low. If you see glitches, add 100 pF capacitors to ground on each line to filter noise. The LPC1768’s I2C controller has a digital filter that rejects pulses shorter than 3 clock cycles, which helps with noise immunity. You can adjust the filter by setting the I2SCLH and I2SCLL values to match the bus speed. For a 400 kHz bus, the filter rejects spikes shorter than 30 ns (3 cycles at 100 MHz).

Finally, consider the display’s driver IC variants. Most 0.96 inch OLEDs use the SSD1306, but some use the SH1106, which has a different memory layout (132x64) and requires different initialization. The SH110