1 of 42

Embedded Development Workshop

Please sign in:

2 of 42

Meme Roundup:

3 of 42

Overview:

BOM:

  • Breadboarding a simple circuit
  • Setting up a development environment
  • Writing code for a display
  • Adding interactivity with an encoder
  • Solderless Breadboard - Self-Adhesive (White)
    • Column Separation: 0.3"
    • Pin Spacing: 0.1"
    • Acceptable wire sizes: 29-20AWG
  • Raspberry Pi Pico WH - Pico Wireless with Headers Soldered
  • USB 2.0 Micro-B Cable
  • 12-step rotary encoder
  • I2C IIC 128X64 0.96" OLED Display Module

4 of 42

Important:

  • Please open these slides on your laptop (link provided in Slack)
  • Windows Users: Ensure you are not working within a OneDrive directory

5 of 42

IDE Setup

Download the Arduino IDE from https://www.arduino.cc/en/software

6 of 42

Wiring Things Up

7 of 42

Breadboard Basics

The pins in each ROW are connected

The pins in the outer COLUMNS are connected

We can use these connections to build a circuit!

8 of 42

Breadboard Basics

Placing something in the middle connects it to both sets of rows

Placing something on one side connects it to a single set of rows

We use jumper wires to connect components

9 of 42

Wiring Diagram

Start with your breadboard laid horizontally in front of you

10 of 42

Wiring Diagram

The Pi goes all the way to the left, with the USB connector facing left�(we did this part for you)

11 of 42

Wiring Diagram

Put the display in the bottom-right corner

12 of 42

Wiring Diagram

The encoder goes here – the rightmost pins of the encoder should be 4 rows in from the edge, so they don’t overlap with the pins of the display

You’ll need to bend the wide legs on either side of the encoder up as pictured to make it fit in the breadboard

(two-pin side facing “up”)

13 of 42

Wiring Diagram

14 of 42

Wiring Diagram

15 of 42

Wiring Diagram

16 of 42

Wiring Diagram

17 of 42

IDE Configuration

18 of 42

IDE Setup

  • Go to the preferences page in the menu bar (one of the following depending on your OS)
    • Arduino IDE → Settings
    • File → Settings
    • File → Preferences
  • Find Additional boards manager URLs
  • Paste the following:

https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

  • Click OK
  • Without doing this properly, the next step won’t work properly

19 of 42

IDE Setup

  • Open Boards Manager (second icon, left sidebar).
  • Search: Raspberry Pi Pico
  • Install the Earle Philhower version, not "Mbed OS" one.

20 of 42

IDE Setup

  • Open Library Manager (third icon, left sidebar).
  • Search: LVGL
  • Install by kisvegabor
  • Use version 8.3.10 only; 9.0.0 incompatible.

21 of 42

Get sample code

  • Download sample code:
    • ZIP File: Download
    • Git users: Clone from GitHub
  • For ease, unzip to Documents/Arduino/nuwc_embedded
  • Open project file. In Arduino IDE, go to:

File > Open > Documents/Arduino/nuwc_embedded > nuwc_embedded.ino

  • Windows Users: Ensure you are not working within a OneDrive directory

22 of 42

Configure LVGL

  • Navigate to Documents/Arduino/nuwc_embedded in File Explorer or Finder.
  • Find lv_conf.h
  • Copy it to Documents/Arduino/libraries/ (or ~/Arduino/libraries/ for Linux/Unix).
  • The lv_conf.h contains configuration options to allow the graphics drawing library to work with the Arduino IDE.

23 of 42

Microcontrollers

24 of 42

Microcontrollers

  • A small computer on a single chip
  • Generally not very powerful/fast
  • Often contain GPIO pins – “General Purpose Input Output”
  • Also contain pins for specific protocols: SPI, I2C, UART…
  • Usually run either an RTOS (real-time operating system) or “bare metal” code

25 of 42

Uploading Code

  • While holding down the BOOTSEL button, plug the Pi Pico into your computer with the USB cable.
  • In the Arduino IDE’s “Tools” menu, choose the following options:
    • The board may initially show up as unknown

    • Board → Raspberry Pi Pico/RP2040Raspberry Pi Pico W
    • Port → UF2_Board
  • Click the “Upload” icon (right arrow in the top left corner)

26 of 42

Task 1: Upload Code

  • You’ll see the display turn on!
  • But the screen contents are probably just noise
  • We’ll fix that in the next steps…

27 of 42

I2C Communication

28 of 42

The I2C Protocol

  • Used to connect microcontrollers with peripherals (sensors, displays, actuators…)
  • Uses only two wires — SCK (a clock signal) and SDA (a data signal)
  • An I2C bus consists of a controller and one or more targets
  • The controller can do two things:
    • Read some number of bytes from a target
    • Write some number of bytes to a target

29 of 42

Our display – the SSD1306

  • The display in your kit is the SSD1306
  • It’s a monochrome, 128x64 display
  • It supports two types of writes:
    • To send commands, write the byte 0x00 followed by the list of commands
    • To send data, write the byte 0x40 followed by your image data
  • Many devices like this will need to run through a sequence of commands at startup to be configured properly
    • Take a peek in ssd1306.cpp to see this yourself!
  • You’ll also need to find a way to transfer data to it…

30 of 42

Task 2: Write Display Data

  • Open the file nuwc_embedded.ino
  • Find the ssd1306_flush function towards the top of the file
  • The first part of the function sets up the display for writing
  • The part with the nested for loops should be writing data to the display, but a few things are missing…
  • Hint: to send a byte of data, use the Wire.write function
    • For instance, to send the byte 0x12, use Wire.write(0x12)
  • Hint: our display supports two types of writes:
    • To send commands, write the byte 0x00 followed by the list of commands
    • To send data, write the byte 0x40 followed by your image data

31 of 42

Task 2: Solution

  • You’ll notice that the existing code begins an I2C transmission at the start, and ends it at the end
  • You need to write data to the screen
  • First: Tell the display that you are sending data by writing 0x40
  • Second: send the byte containing the image data

Wire.beginTransmission(I2C_ADDR);

Wire.write(0x40);

Wire.write(data_byte);

Wire.endTransmission();

32 of 42

Task 2: Upload code

  • Upload this code (you may need to unplug and replug the Pi Pico)
  • You should see a message appear!
  • Try changing the message in the code and see that the display is updated
    • Remember, you’ll need to replug every time you upload

33 of 42

Graphics with LVGL

34 of 42

LVGL

  • We have a lot of tools for programming user interfaces
    • Websites: HTML, CSS, JavaScript, WebGL…
    • Desktop: Tkinter, Qt, GTK, ImGUI, Iced, OpenGL…
    • Android: Views, Compose…
    • iOS: Storyboard, SwiftUI…
  • Most of these are way too complex to run on a microcontroller
  • Enter LVGL: the Lightweight and Versatile Graphics Library

35 of 42

Task 3: LVGL Labels and Buttons

  • Find the three lines that create the label you see on the screen, and comment them out for now
  • Uncomment the following lines, starting with cont_row and ending with lv_indev_set_group (the keyboard shortcut is Ctrl+/)
  • Upload code again!
  • These buttons don’t do anything (yet…)

36 of 42

Interrupts

37 of 42

Rotary Encoders

  • The knob in your kit is called a�“rotary encoder” or “quadrature encoder”
  • Notice that you can rotate it infinitely
  • You can also click it

38 of 42

Rotary Encoder Signals

  • The rotating part of the encoder has two signals
  • When one signal goes from “high” to “low,” we can look at the other signal to see if the encoder turned left or right

39 of 42

Rotary Encoder Signals: Interrupts

  • One problem: rotary encoders can spin very fast, and our microcontroller runs quite slowly by comparison
  • What happens if we don’t check it frequently enough and we miss a tick?
  • If only we could “interrupt” the microcontroller whenever a pulse comes in so we can check which direction the encoder spun…
  • Many microcontrollers support this – it’s called an interrupt
  • When a condition happens, the microcontroller calls an interrupt service routine (ISR)

40 of 42

Task 4: Encoder ISR

  • Find the encoder_isr function in the starter code
  • Look at the sections marked TODO – something’s missing
  • Add the needed lines to make the encoder work as expected
  • Hint: the current number of encoder ticks is stored in the encoder_ticks variable

41 of 42

Task 4: Encoder ISR

  • Find the encoder_isr function in the starter code
  • Look at the sections marked TODO – something’s missing
  • Add the needed lines to make the encoder work as expected

if (data) {

++encoder_ticks;

} else {

--encoder_ticks;

}

42 of 42

Thanks for coming!

Next week: Bare Metal Embedded Development on STM32

Before leaving, please return your kit to the front of the room! They will be reused in future workshops. No need to disassemble anything before returning.