Hello Hobbyist, Today I’m going to demonstrate SSD1306 with Raspberry Pi Pico. Pico is recently launched and it’s libraries are not that developed. But today we are going to perform connecting this Oled to pico via SPI communication. All code and libraries are given so don’t worry. Let’s Begin then
Raspberry Pi Pico is development board which runs basically on MicroPython. It is similar to other microcontrollers like Arduino, NodeMCU and various other. But it has some more features as compared to them. It is built out of RP2040. It has 264KB of RAM and 2MB of FLASH space. You can also program PICO in C/C++ using arduino IDE. For that just include this link in your Arduino IDE preferences options. Then go to Boards manager and search Raspberry pi pico and download this Boards.
Using this you can use all type of communication like SPI(2), I2C(2),UART, Serial. So is you are well good in python then you just try this board for sure. The library which you have to use for intalling firmware onto board can easily be done. By using Thonny IDE.
For updating the firmware or installing just press the button(BOOTSEL) on PICO and while pressing connect usb to pico. Once your board is detected in Thonny IDE you can release the button. Now click ‘Install or Upgrade Firmware” option available on bottom right.
- raspberry Pi Pico
- SSD1306 SPI OLED
- Jumper Wires
- Thonny IDE installed on system
Open Thonny IDE and then Paste this code in a new file:
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces from micropython import const import framebuf SET_CONTRAST = const(0x81) SET_ENTIRE_ON = const(0xA4) SET_NORM_INV = const(0xA6) SET_DISP = const(0xAE) SET_MEM_ADDR = const(0x20) SET_COL_ADDR = const(0x21) SET_PAGE_ADDR = const(0x22) SET_DISP_START_LINE = const(0x40) SET_SEG_REMAP = const(0xA0) SET_MUX_RATIO = const(0xA8) SET_COM_OUT_DIR = const(0xC0) SET_DISP_OFFSET = const(0xD3) SET_COM_PIN_CFG = const(0xDA) SET_DISP_CLK_DIV = const(0xD5) SET_PRECHARGE = const(0xD9) SET_VCOM_DESEL = const(0xDB) SET_CHARGE_PUMP = const(0x8D) class SSD1306(framebuf.FrameBuffer): def __init__(self, width, height, external_vcc): self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): for cmd in ( SET_DISP | 0x00, # off # address setting SET_MEM_ADDR, 0x00, # horizontal # resolution and layout SET_DISP_START_LINE | 0x00, SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 SET_MUX_RATIO, self.height - 1, SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 SET_DISP_OFFSET, 0x00, SET_COM_PIN_CFG, 0x02 if self.width > 2 * self.height else 0x12, # timing and driving scheme SET_DISP_CLK_DIV, 0x80, SET_PRECHARGE, 0x22 if self.external_vcc else 0xF1, SET_VCOM_DESEL, 0x30, # 0.83*Vcc # display SET_CONTRAST, 0xFF, # maximum SET_ENTIRE_ON, # output follows RAM contents SET_NORM_INV, # not inverted # charge pump SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, SET_DISP | 0x01, ): # on self.write_cmd(cmd) self.fill(0) self.show() def poweroff(self): self.write_cmd(SET_DISP | 0x00) def poweron(self): self.write_cmd(SET_DISP | 0x01) def contrast(self, contrast): self.write_cmd(SET_CONTRAST) self.write_cmd(contrast) def invert(self, invert): self.write_cmd(SET_NORM_INV | (invert & 1)) def show(self): x0 = 0 x1 = self.width - 1 if self.width == 64: # displays with width of 64 pixels are shifted by 32 x0 += 32 x1 += 32 self.write_cmd(SET_COL_ADDR) self.write_cmd(x0) self.write_cmd(x1) self.write_cmd(SET_PAGE_ADDR) self.write_cmd(0) self.write_cmd(self.pages - 1) self.write_data(self.buffer) class SSD1306_I2C(SSD1306): def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): self.i2c = i2c self.addr = addr self.temp = bytearray(2) self.write_list = [b"\x40", None] # Co=0, D/C#=1 super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.temp = 0x80 # Co=1, D/C#=0 self.temp = cmd self.i2c.writeto(self.addr, self.temp) def write_data(self, buf): self.write_list = buf self.i2c.writevto(self.addr, self.write_list) class SSD1306_SPI(SSD1306): def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): self.rate = 10 * 1024 * 1024 dc.init(dc.OUT, value=0) res.init(res.OUT, value=0) cs.init(cs.OUT, value=1) self.spi = spi self.dc = dc self.res = res self.cs = cs import time self.res(1) time.sleep_ms(1) self.res(0) time.sleep_ms(10) self.res(1) super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(0) self.cs(0) self.spi.write(bytearray([cmd])) self.cs(1) def write_data(self, buf): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(1) self.cs(0) self.spi.write(buf) self.cs(1)
Save this file in your pico with name ‘ssd1306.py’. This is not the main code but it helps up to run the main code or you can say that it is library which is used.
Now the main code work like this. First we import SPI and Pin functions from machine module. Then we import SSD1306_SPI function from library saved above (Use SSD1306_I2C for I2C communication). After it we import module which contains all processing that we gonna do to display things on oled. Alsowe import some time modules for delay in program.
from machine import Pin, SPI from ssd1306 import SSD1306_SPI import framebuf from time import sleep from utime import sleep_ms
Now we define to which SPI port we gonna hook our OLED i.e., SPI(0). PIns for SPI are 18,19,16,17; SCK, MOSI, MISO, CS respectively. Pins for dc and rst can be defined manually in SSD1306 OLED initialization. Also, we create an object ‘oled’ which stores the initialization of our OLED
spi = SPI(0, 100000, mosi=Pin(19), sck=Pin(18)) oled = SSD1306_SPI(128, 64, spi, Pin(17),Pin(20), Pin(16))
after this in the while loop we apply to try and except method to make the loop continue until a keyboard interrupt is encountered. So display will show text ‘HELLO WORLD’ scrolling down and right at the same time until we give keyboard interrupt.
Here is the complete code. Just have a look and remember to save it with the name ‘main.py’ in pico so that it runs whenever pico gets restarted or powered on.
from machine import Pin, SPI from ssd1306 import SSD1306_SPI import framebuf from time import sleep from utime import sleep_ms spi = SPI(0, 100000, mosi=Pin(19), sck=Pin(18)) oled = SSD1306_SPI(128, 64, spi, Pin(17),Pin(20), Pin(16)) #oled = SSD1306_SPI(WIDTH, HEIGHT, spi, dc,rst, cs) use GPIO PIN NUMBERS while True: try: for i in range(40): for j in range(56): oled.fill(0) oled.show() #sleep(1) oled.text("HELLO WORLD",i,j) oled.show() sleep_ms(10) except KeyboardInterrupt: break
With this, we have successfully completed our tutorial on SSD1306 raspberry Pi Pico using SPI communication. I hope you liked it. If you come through and problem then let me know in the comment down below.