Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ App|Description
[spi_dma](spi/spi_dma) | Use DMA to transfer data both to and from the SPI simultaneously. The SPI is configured for loopback.
[spi_flash](spi/spi_flash) | Erase, program and read a serial flash device attached to one of the SPI controllers.
[spi_master_slave](spi/spi_master_slave) | Demonstrate SPI communication as master and slave.
[ssd1309_stdout_spi](spi/ssd1309_stdout_spi/) | Display text from stdout and simple graphics on an SSD1309-based OLED panel via SPI.
[max7219_8x7seg_spi](spi/max7219_8x7seg_spi) | Attaching a Max7219 driving an 8 digit 7 segment display via SPI.
[max7219_32x8_spi](spi/max7219_32x8_spi) | Attaching a Max7219 driving an 32x8 LED display via SPI.

Expand Down
1 change: 1 addition & 0 deletions spi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ if (TARGET hardware_spi)
add_subdirectory_exclude_platforms(spi_dma)
add_subdirectory_exclude_platforms(spi_master_slave)
add_subdirectory_exclude_platforms(spi_flash)
add_subdirectory_exclude_platforms(ssd1309_stdout_spi)
add_subdirectory_exclude_platforms(max7219_32x8_spi)
add_subdirectory_exclude_platforms(max7219_8x7seg_spi)
else()
Expand Down
16 changes: 16 additions & 0 deletions spi/ssd1309_stdout_spi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
add_executable(ssd1309_stdout_spi
ssd1309_stdout_spi.c
)

# pull in common dependencies and additional hardware support
target_link_libraries(ssd1309_stdout_spi
pico_stdlib
hardware_spi
hardware_dma
)

# create map/bin/hex file etc.
pico_add_extra_outputs(ssd1309_stdout_spi)

# add url via pico_set_program_url
example_auto_set_url(ssd1309_stdout_spi)
59 changes: 59 additions & 0 deletions spi/ssd1309_stdout_spi/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
= Simple graphics and stdout text on an OLED display via SPI

This example displays text and graphics on one of the widely-available small OLED panels based on the *SSD1309* controller. It should also work with compatible devices such as the *SSD1306* (not tested).

These modules typically support either I2C or SPI. For this example you will need one configured for SPI.

The code renders content onto a frame buffer that is transferred to the SPI port in the background, by a DMA channel under the control of a frame timer. A simple driver is used to copy _stdout_ to the frame buffer and some basic graphics functions are provided.

The interface uses one of the Pico's onboard SPI peripherals and two extra GPIO pins as shown below. Note that in SPI mode the SSD1309 is a receive-only device.

For details of the commands supported by the SSD1309 controller and its addressing modes see the manufacturer's datasheet: https://www.hpinfotech.ro/SSD1309.pdf.


== Wiring information

Wiring up the device requires seven jumpers as follows:

* Display CS (chip select) -> Pico GP17 (SPI0 CSn), pin 22
* Display DC (data/command) -> Pico GP20, pin 26
* Display RES (reset) -> Pico GP21, pin 27
* Display SDA (MOSI) -> Pico GP19 (SPI0 TX), pin 25
* Display SCLK (SPI clock) -> Pico GP18 (SPI0 SCK), pin 24
* Display VDD (3.3v) -> Pico 3V3_OUT, pin 36
* Display VSS (0v, gnd) -> Pico GND, pin 23

The example uses SPI device 0 and powers the display from the Pico 3.3v output. If you power the display from an external supply then ensure that the Pico's logic pins are not exposed to any voltage higher than 3.3v.

[NOTE]
======
The pins on your board may be labelled slightly differently to the list above. Check the documentation for your display.

You can change the code to use different pins if you like, but the ones for CSn, TX and SCK must match your SPI device: see the GPIO Function Select Table in the datasheet.
======


[[wiring_diagram.png]]
[pdfwidth=75%]
.Wiring Diagram for SSD1309 with SPI interface
image::wiring_diagram.png[]

== List of Files

CMakeLists.txt:: A file to configure the CMake build system for the example.
ssd1309_stdout_spi.c:: The example code.
font.h:: A basic 8x8 bit font table used by the example.


== Bill of Materials

.A list of materials required for the example
[[SSD1309-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico or Pico 2 | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| SSD1309-based OLED display panel with SPI interface| 1 | generic part
| M/F Jumper wires (assorted colours) | 7 | generic part
|===
118 changes: 118 additions & 0 deletions spi/ssd1309_stdout_spi/font.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* Copyright (c) 2026 mjcross
*
* SPDX-License-Identifier: BSD-3-Clause
**/

// Vertical bitmaps for commonly-used characters.

// Each bitmap is 8 pixels wide and 8 pixels high, with the least significant bit
// at the top. The bitmaps were translated from one of the original IBM BIOS fonts
// released over 45yrs ago (see https://int10h.org/oldschool-pc-fonts/)

#include <stdint.h>

#define FONT_INDEX_UNDEF 0
#define FONT_INDEX_START 1
#define FONT_CODE_FIRST 32
#define FONT_CODE_LAST 126
#define FONT_BYTES_PER_CODE 8

static const uint8_t font[] = {
0xff, 0xfd, 0xfe, 0xfe, 0xae, 0xf6, 0xf9, 0xff, // 00 (code -1) default
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 01 (code 32) space
0x00, 0x00, 0x0c, 0xbe, 0x0c, 0x00, 0x00, 0x00, // 02 (code 33) exclam
0x00, 0x00, 0x0e, 0x00, 0x00, 0x0e, 0x00, 0x00, // 03 (code 34) quotedbl
0x00, 0x28, 0xfe, 0x28, 0x28, 0xfe, 0x28, 0x00, // 04 (code 35) numbersign
0x00, 0x48, 0x54, 0xd6, 0xd6, 0x54, 0x24, 0x00, // 05 (code 36) dollar
0x00, 0x8c, 0x4c, 0x20, 0x10, 0xc8, 0xc4, 0x00, // 06 (code 37) percent
0x60, 0x94, 0x8a, 0x9a, 0x64, 0x90, 0x90, 0x00, // 07 (code 38) ampersand
0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, // 08 (code 39) quotesingle
0x00, 0x38, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, // 09 (code 40) parenleft
0x00, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, // 10 (code 41) parenright
0x10, 0x54, 0x38, 0x38, 0x38, 0x54, 0x10, 0x00, // 11 (code 42) asterisk
0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, // 12 (code 43) plus
0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, // 13 (code 44) comma
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, // 14 (code 45) hyphen
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, // 15 (code 46) period
0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, // 16 (code 47) slash
0x00, 0x7c, 0xc2, 0xa2, 0x92, 0x8a, 0x7c, 0x00, // 17 (code 48) zero
0x00, 0x88, 0x84, 0xfe, 0x80, 0x80, 0x00, 0x00, // 18 (code 49) one
0x00, 0xc4, 0xa2, 0xa2, 0x92, 0x92, 0xcc, 0x00, // 19 (code 50) two
0x00, 0x44, 0x82, 0x92, 0x92, 0x92, 0x6c, 0x00, // 20 (code 51) three
0x20, 0x30, 0x28, 0xa4, 0xfe, 0xa0, 0x20, 0x00, // 21 (code 52) four
0x00, 0x4e, 0x8a, 0x8a, 0x8a, 0x8a, 0x72, 0x00, // 22 (code 53) five
0x00, 0x78, 0x94, 0x92, 0x92, 0x92, 0x60, 0x00, // 23 (code 54) six
0x00, 0x06, 0x02, 0xe2, 0x12, 0x0a, 0x06, 0x00, // 24 (code 55) seven
0x00, 0x6c, 0x92, 0x92, 0x92, 0x92, 0x6c, 0x00, // 25 (code 56) eight
0x00, 0x0c, 0x92, 0x92, 0x92, 0x52, 0x3c, 0x00, // 26 (code 57) nine
0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, // 27 (code 58) colon
0x00, 0x00, 0x80, 0x66, 0x00, 0x00, 0x00, 0x00, // 28 (code 59) semicolon
0x00, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, // 29 (code 60) less
0x00, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x00, // 30 (code 61) equal
0x00, 0x00, 0x00, 0x82, 0x44, 0x28, 0x10, 0x00, // 31 (code 62) greater
0x00, 0x04, 0x02, 0x02, 0xa2, 0x12, 0x0c, 0x00, // 32 (code 63) question
0x00, 0x7c, 0x82, 0xba, 0xaa, 0xaa, 0x3c, 0x00, // 33 (code 64) at
0x00, 0xf8, 0x24, 0x22, 0x22, 0x24, 0xf8, 0x00, // 34 (code 65) A
0x00, 0x82, 0xfe, 0x92, 0x92, 0x92, 0x6c, 0x00, // 35 (code 66) B
0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x00, // 36 (code 67) C
0x00, 0x82, 0xfe, 0x82, 0x82, 0x44, 0x38, 0x00, // 37 (code 68) D
0x00, 0x82, 0xfe, 0x92, 0xba, 0x82, 0xc6, 0x00, // 38 (code 69) E
0x00, 0x82, 0xfe, 0x92, 0x3a, 0x02, 0x06, 0x00, // 39 (code 70) F
0x00, 0x38, 0x44, 0x82, 0xa2, 0xa2, 0xe4, 0x00, // 40 (code 71) G
0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0xfe, 0x00, // 41 (code 72) H
0x00, 0x00, 0x82, 0xfe, 0x82, 0x00, 0x00, 0x00, // 42 (code 73) I
0x00, 0x60, 0x80, 0x80, 0x82, 0x7e, 0x02, 0x00, // 43 (code 74) J
0x00, 0x82, 0xfe, 0x10, 0x28, 0x44, 0x82, 0x80, // 44 (code 75) K
0x00, 0x82, 0xfe, 0x82, 0x80, 0x80, 0xc0, 0x00, // 45 (code 76) L
0x00, 0xfe, 0x02, 0x04, 0x08, 0x04, 0x02, 0xfe, // 46 (code 77) M
0x00, 0xfe, 0x02, 0x04, 0x08, 0x10, 0xfe, 0x00, // 47 (code 78) N
0x00, 0x38, 0x44, 0x82, 0x82, 0x44, 0x38, 0x00, // 48 (code 79) O
0x00, 0x82, 0xfe, 0x92, 0x12, 0x12, 0x0c, 0x00, // 49 (code 80) P
0x00, 0x3c, 0x42, 0x42, 0x62, 0x42, 0xbc, 0x80, // 50 (code 81) Q
0x00, 0x82, 0xfe, 0x92, 0x32, 0x52, 0x8c, 0x00, // 51 (code 82) R
0x00, 0x4c, 0x92, 0x92, 0x92, 0x92, 0x64, 0x00, // 52 (code 83) S
0x00, 0x06, 0x02, 0x82, 0xfe, 0x82, 0x02, 0x06, // 53 (code 84) T
0x00, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x7e, 0x00, // 54 (code 85) U
0x00, 0x1e, 0x20, 0x40, 0x80, 0x40, 0x20, 0x1e, // 55 (code 86) V
0x00, 0x7e, 0x80, 0x80, 0x70, 0x80, 0x80, 0x7e, // 56 (code 87) W
0x00, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, // 57 (code 88) X
0x00, 0x02, 0x04, 0x88, 0xf0, 0x88, 0x04, 0x02, // 58 (code 89) Y
0x00, 0x86, 0xc2, 0xa2, 0x92, 0x8a, 0x86, 0xc2, // 59 (code 90) Z
0x00, 0xfe, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, // 60 (code 91) bracketleft
0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, // 61 (code 92) backslash
0x00, 0x82, 0x82, 0x82, 0xfe, 0x00, 0x00, 0x00, // 62 (code 93) bracketright
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, // 63 (code 94) asciicircum
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 64 (code 95) underscore
0x00, 0x00, 0x00, 0x06, 0x08, 0x00, 0x00, 0x00, // 65 (code 96) grave
0x00, 0x40, 0xa8, 0xa8, 0xa8, 0xa8, 0xf0, 0x80, // 66 (code 97) a
0x00, 0x02, 0xfe, 0x60, 0x90, 0x90, 0x90, 0x60, // 67 (code 98) b
0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x50, 0x00, // 68 (code 99) c
0x00, 0x60, 0x90, 0x90, 0x90, 0x62, 0xfe, 0x80, // 69 (code 100) d
0x00, 0x70, 0xa8, 0xa8, 0xa8, 0xa8, 0x30, 0x00, // 70 (code 101) e
0x00, 0x00, 0x90, 0xfc, 0x92, 0x02, 0x04, 0x00, // 71 (code 102) f
0x00, 0x98, 0xa4, 0xa4, 0xa4, 0xa4, 0x78, 0x04, // 72 (code 103) g
0x00, 0x82, 0xfe, 0x10, 0x08, 0x08, 0xf0, 0x00, // 73 (code 104) h
0x00, 0x00, 0x88, 0xfa, 0x80, 0x00, 0x00, 0x00, // 74 (code 105) i
0x00, 0x60, 0x80, 0x80, 0x80, 0x84, 0x7d, 0x00, // 75 (code 106) j
0x00, 0x02, 0xfe, 0x20, 0x50, 0x88, 0x80, 0x00, // 76 (code 107) k
0x00, 0x00, 0x82, 0xfe, 0x80, 0x00, 0x00, 0x00, // 77 (code 108) l
0x00, 0xf8, 0x08, 0x08, 0xf0, 0x08, 0x08, 0xf0, // 78 (code 109) m
0x00, 0xf8, 0x10, 0x08, 0x08, 0x08, 0xf0, 0x00, // 79 (code 110) n
0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, // 80 (code 111) o
0x00, 0x84, 0xfc, 0x98, 0x24, 0x24, 0x18, 0x00, // 81 (code 112) p
0x00, 0x18, 0x24, 0x24, 0x98, 0xfc, 0x84, 0x00, // 82 (code 113) q
0x00, 0x88, 0xf8, 0x90, 0x08, 0x08, 0x30, 0x00, // 83 (code 114) r
0x00, 0x90, 0xa8, 0xa8, 0xa8, 0xa8, 0x48, 0x00, // 84 (code 115) s
0x00, 0x08, 0x08, 0x7e, 0x88, 0x88, 0x40, 0x00, // 85 (code 116) t
0x00, 0x78, 0x80, 0x80, 0x80, 0x40, 0xf8, 0x00, // 86 (code 117) u
0x00, 0x18, 0x20, 0x40, 0x80, 0x40, 0x20, 0x18, // 87 (code 118) v
0x00, 0x78, 0x80, 0x80, 0x70, 0x80, 0x80, 0x78, // 88 (code 119) w
0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x00, // 89 (code 120) x
0x00, 0x9c, 0xa0, 0xa0, 0xa0, 0xa0, 0x7c, 0x00, // 90 (code 121) y
0x00, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x00, 0x00, // 91 (code 122) z
0x00, 0x10, 0x10, 0x6c, 0x82, 0x82, 0x00, 0x00, // 92 (code 123) braceleft
0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, // 93 (code 124) bar
0x00, 0x00, 0x82, 0x82, 0x6c, 0x10, 0x10, 0x00, // 94 (code 125) braceright
0x00, 0x04, 0x02, 0x02, 0x04, 0x04, 0x02, 0x00 // 95 (code 126) asciitilde
};
Loading