How to use a 0.96 inch OLED with a STM32F103?

By admin

How to use a 0.96 inch OLED with a STM32F103

To use a 0.96 inch OLED with a STM32F103, you wire the display’s I2C pins (SDA and SCL) to the microcontroller’s PB7 and PB6 respectively, set up the I2C peripheral in your firmware, and initialize the OLED driver (typically the SSD1306) with a 128x64 pixel buffer. The STM32F103C8T6, running at 72 MHz, can refresh the display at over 30 frames per second using a 400 kHz I2C clock, which is fast enough for dynamic data like sensor readings or simple animations. The most common display module is the 0.96 inch 128x64 i2c oled display, which uses the SSD1306 controller over I2C, with a default address of 0x3C (or 0x3D if the SA0 pin is pulled high). You need to handle the initialization sequence, which involves sending a series of command bytes to set up the display’s multiplex ratio, segment remap, COM pins, contrast, and display on/off. The STM32F103’s I2C module must be configured as master with a clock speed of 100 kHz or 400 kHz, and you’ll use the HAL_I2C_Mem_Write() function to send commands and data, or you can write your own register-level code for lower latency. The display consumes about 20 mA at 3.3V, so you can power it directly from the STM32’s 3.3V output, but add a 10 µF capacitor between VCC and GND near the display to filter noise. The pixel buffer is 1024 bytes (128 columns × 64 rows / 8 bits per row), which fits easily in the STM32F103’s 20 KB SRAM. You update the buffer in RAM, then send the entire buffer to the display via the I2C data stream, which takes about 25 ms at 400 kHz. For real-time applications, you can use double buffering to avoid tearing artifacts. The OLED’s contrast is adjustable via the 0x81 command, with values from 0x00 (off) to 0xFF (max), and typical usage sets it around 0x7F. The display’s viewing angle is about 160 degrees, and its response time is under 10 µs, making it suitable for fast-changing data like oscilloscope waveforms or live sensor graphs. The operating temperature range is -40°C to +85°C, which covers most industrial applications. The STM32F103’s I2C bus must have pull-up resistors, typically 4.7 kΩ to 3.3V, because the OLED module does not include them. If you use a 100 kHz clock, the bus capacitance limit is about 400 pF, which is fine for short wires under 10 cm. For longer runs, use 2.2 kΩ pull-ups and consider shielded twisted pair for the SDA and SCL lines. The SSD1306 supports page addressing mode, horizontal addressing mode, and vertical addressing mode; horizontal mode is the most efficient for full-screen updates because you can send all 1024 bytes sequentially without resetting the column and page pointers. The initialization sequence takes about 10 ms, during which the display is blank. After initialization, you can clear the display by sending 0x00 for all bytes, then write your pixel data. The display’s memory is organized as 8 pages (rows 0-7), each page containing 128 columns, and each column is 8 bits (one byte representing 8 vertical pixels). To draw a pixel at (x, y), you calculate the page as y / 8, the bit position as y % 8, and then set or clear that bit in the buffer. For text rendering, use a 5x7 font, which gives 21 characters per line and 8 lines, or a 6x8 font for 21 characters per line and 8 lines with better spacing. The STM32F103’s I2C peripheral can be configured to use DMA for automatic data transfer, which frees the CPU during display updates. For example, you can set up a DMA channel to transfer the buffer from SRAM to the I2C data register, with the I2C configured to generate a stop condition after the transfer completes. This reduces CPU load from 25 ms to about 2 µs for the DMA setup overhead. The display’s power consumption drops to about 0.1 mA in sleep mode, which you enter by sending the 0xAE command. Wake it up with 0xAF. The STM32F103 can also drive the display via SPI, but the I2C version uses only two wires (plus power and ground), which is simpler for breadboard or prototype setups. The I2C bus speed of 400 kHz yields a theoretical maximum of 400 kbps, but the actual data throughput is lower due to addressing, control bytes, and ACK/NACK bits. For a full screen update, you send 1024 data bytes plus 2 bytes per 16-byte block (the I2C write protocol), totaling about 1152 bytes, which takes 23 ms at 400 kHz (1152 bytes × 10 bits per byte / 400 kbps). This is acceptable for most applications, but if you need faster updates, use SPI mode, which can achieve 10 MHz clock speed, reducing full-screen update time to under 1 ms. The STM32F103’s SPI can run at up to 18 MHz, so you can easily hit 10 MHz. However, the I2C version is more common and easier to wire. The display’s logic level is 3.3V, so it’s compatible with the STM32F103’s GPIO pins without level shifting. The I2C address is set by the SA0 pin on the OLED module; if it’s not broken out, the address is fixed at 0x3C. You can verify the address using an I2C scanner sketch. The STM32F103’s I2C peripheral has a 7-bit addressing mode, so you shift the address left by 1 bit for the write operation (0x78 for address 0x3C). The HAL library handles this automatically. The display’s brightness is uniform across the entire 0.96-inch diagonal, with a typical luminance of 100 cd/m² at full contrast. The pixel pitch is about 0.17 mm, giving a sharp image. The display’s lifetime is rated at 50,000 hours to half brightness, which is typical for OLEDs. The STM32F103’s I2C module can be configured to generate interrupts on each byte transfer, but for simplicity, polling mode works fine for non-critical applications. The initialization sequence for the SSD1306 includes the following commands: 0xAE (display off), 0xD5 (display clock divide ratio/oscillator frequency), 0x80 (default), 0xA8 (multiplex ratio), 0x3F (64 rows), 0xD3 (display offset), 0x00 (no offset), 0x40 (start line 0), 0x8D (charge pump), 0x14 (enable charge pump), 0x20 (memory addressing mode), 0x00 (horizontal mode), 0xA1 (segment remap, column 127 mapped to SEG0), 0xC8 (COM output scan direction, remapped mode), 0xDA (COM pins hardware configuration), 0x12 (alternative pin configuration), 0x81 (contrast), 0x7F (default), 0xD9 (pre-charge period), 0xF1 (default), 0xDB (VCOMH deselect level), 0x40 (default), 0xA4 (entire display on, resume to RAM content), 0xA6 (normal display, not inverted), 0x2E (deactivate scroll), 0xAF (display on). This sequence takes about 25 bytes, which you send over I2C. The display’s RAM is write-only, so you cannot read back pixel data. If you need to modify individual pixels, you must maintain a buffer in RAM. The STM32F103’s 20 KB SRAM is more than enough for the 1 KB buffer, plus room for other variables. For graphics, use a library like u8g2 or Adafruit_SSD1306, but these libraries are designed for Arduino and may need porting to STM32 HAL. A simpler approach is to write your own functions for drawing pixels, lines, rectangles, and text. For example, a function to draw a line uses Bresenham’s algorithm, which requires only integer arithmetic and runs in microseconds on the 72 MHz Cortex-M3. The display’s refresh rate is limited by the I2C speed, not the STM32’s processing power. The STM32F103 can execute about 72 million instructions per second, so rendering a full screen of graphics takes under 1 ms, but the I2C transfer takes 23 ms. This means the display update is the bottleneck. To improve perceived performance, update only the changed regions of the screen. For example, if you update a single 16x16 pixel icon, you only need to send 32 bytes (16 columns × 16 rows / 8 bits per row), which takes about 0.64 ms at 400 kHz. The display’s I2C interface supports clock stretching, but the STM32F103’s I2C peripheral can handle it automatically. The OLED module typically has a built-in DC-DC converter for the OLED drive voltage, which generates about 7-15V from the 3.3V supply. This converter can cause noise on the power line, so the 10 µF capacitor is essential. The STM32F103’s ADC is not affected because the OLED is a separate module. The display’s viewing angle is nearly 180 degrees, and it has no backlight, so it’s readable in direct sunlight if the contrast is set high. The typical power consumption is 20 mA with all pixels on, but it drops to 10 mA with a typical pattern like text. The STM32F103’s 3.3V regulator can supply up to 150 mA, so the OLED is not a problem. For battery-powered applications, use the display’s sleep mode and update the screen only when needed. The initialization sequence takes about 10 ms, so you can turn the display on and off quickly. The display’s I2C bus can be shared with other devices, like a temperature sensor or an accelerometer, as long as the addresses don’t conflict. The STM32F103’s I2C peripheral supports multiple masters, but for simplicity, use single master mode. The bus capacitance should be kept under 400 pF for 400 kHz operation, which limits the total wire length to about 2 meters. The display’s module size is 27.3 mm × 27.8 mm, with a thickness of 4.3 mm, so it fits in small enclosures. The mounting holes are 2.5 mm diameter, spaced 24 mm apart. The STM32F103’s GPIO pins can sink or source up to 25 mA, so you can directly drive the OLED’s I2C lines without a buffer. The I2C pull-up resistors should be connected to 3.3V, not 5V, to avoid damaging the OLED’s logic. The display’s datasheet specifies an absolute maximum rating of 3.6V for VCC, so 3.3V is safe. The STM32F103’s I2C pins are 5V tolerant, but the OLED is not, so use 3.3V logic. The display’s contrast can be adjusted dynamically based on ambient light, using a photoresistor connected to the STM32F103’s ADC. For example, read the ADC value, map it to a contrast range of 0x00 to 0xFF, and send the 0x81 command with the new value. This improves readability in varying light conditions. The display’s response time is under 10 µs, so it can show fast-moving objects without blur. The STM32F103’s timers can generate PWM signals for backlight dimming, but the OLED has no backlight, so this is not applicable. The display’s pixel structure is passive matrix, so each pixel is driven by a capacitor that holds the charge between refreshes. The refresh rate must be at least 60 Hz to avoid flicker, but the SSD1306 handles this internally with an oscillator. The STM32F103 does not need to send refresh commands; just update the RAM when needed. The display’s internal oscillator runs at about 500 kHz, which generates the frame rate. The display’s datasheet specifies a minimum frame rate of 50 Hz, but the default is higher. The STM32F103’s I2C communication can be debugged using a logic analyzer, which shows the start condition, address byte, ACK/NACK, data bytes, and stop condition. The typical waveform for a write to the display is: start, 0x78 (write address), ACK, 0x00 (control byte for command), ACK, command byte, ACK, stop. For data writes, the control byte is 0x40. The display’s I2C bus can be operated at 100 kHz for compatibility with slower devices, but 400 kHz is standard. The STM32F103’s I2C peripheral has a programmable clock divider, so you can set any speed up to 400 kHz. The display’s driver IC, the SSD1306, has a built-in charge pump that generates the high voltage for the OLED pixels. The charge pump can be disabled in sleep mode to save power. The STM32F103’s low-power modes can put the CPU to sleep while the display is off, waking up on an interrupt from a button or timer. The display’s initialization sequence can be stored in flash memory as a constant array, and the HAL_I2C_Mem_Write() function can send it in one call. The STM32F103’s flash memory is 64 KB or 128 KB, so storing the 25-byte sequence is trivial. The display’s pixel buffer can be defined as a global array of 1024 uint8_t, which is allocated in SRAM. The STM32F103’s linker script must ensure enough heap space if you use dynamic allocation, but static allocation is simpler. The display’s I2C address can be changed by modifying the SA0 pin on the module, but most modules have it fixed. The STM32F103’s I2C peripheral can handle clock stretching from the display, which occurs when the display is busy processing the previous command. The timeout for clock stretching should be set to at least 10 ms in the I2C configuration. The display’s datasheet specifies a maximum clock frequency of 400 kHz for I2C, but some modules work at 1 MHz if the bus capacitance is low. The STM32F103’s I2C peripheral can run at up to 400 kHz in standard mode, but fast mode plus is not supported. The display’s pixel format is monochrome, so each pixel is either on or off. There is no grayscale. The display’s contrast is adjusted by the charge pump voltage, not by PWM. The STM32F103’s DAC can generate an analog voltage for contrast control, but the SSD1306 uses a digital command, so this is not needed. The display’s viewing angle is symmetric, so it looks the same from all directions. The display’s polarizer is circular, which reduces glare. The display’s module has a built-in level shifter for the I2C lines, so it can interface with 3.3V or 5V logic, but 3.3V is recommended. The STM32F103’s I2C pins are open-drain, so the pull-up resistors are essential. The display’s power consumption is proportional to the number of pixels on, so a mostly black screen uses less power than a mostly white screen. The STM32F103’s power consumption is about 50 mA at 72 MHz, so the total system power is about 70 mA with the display on. For battery-powered applications, use a 500 mAh battery for about 7 hours of continuous operation. The display’s startup time from power-on is about 10 ms, during which the charge pump stabilizes. The STM32F103’s startup time is about 1 ms, so the system is ready quickly. The display’s I2C bus can be reset by toggling the power or by sending a software reset command (0x21). The STM32F103’s I2C peripheral can be reset by the RCC peripheral reset register. The display’s driver IC supports horizontal scrolling, which you can activate by sending the scroll commands. This is useful for marquee text without CPU intervention. The scroll speed is set by the 0x26 or 0x27 command, with parameters for start page, end page, and frame rate. The STM32F103 can send these commands once, and the display handles the scrolling internally. The display’s memory is organized as a 128x64 bit matrix, which is 1024 bytes. The STM32F103 can access this buffer as a 2D array, where buffer[y/8][x] is the byte for column x and page y/8. The bit position within the byte is y%8. This layout is efficient for vertical operations. The display’s I2C interface supports burst writes, so you can send all 1024 bytes in one transaction. The STM32F103’s I2C peripheral can handle up to 255 bytes per transaction in hardware, but for larger transfers, you need to use repeated start or DMA. The HAL library supports multi-byte transfers with the HAL_I2C_Mem_Write() function, which handles the control byte and data bytes automatically. The display’s datasheet specifies that the I2C bus must be idle for at least 1.3 µs between transactions, which is automatically satisfied by the STM32F103’s I2C peripheral. The display’s pixel lifetime is about 50,000 hours for typical use, but it degrades faster if the display is always on with high contrast. The STM32F103 can implement a screen saver that turns off the display after a period of inactivity. The display’s contrast can be set to a lower value for longer life. The display’s operating temperature range is -40