Skip to content

Commit

Permalink
oled section
Browse files Browse the repository at this point in the history
  • Loading branch information
ImplFerris committed Oct 26, 2024
1 parent 1665eb5 commit 0c5cbd0
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
- [Light it Up](./ultrasonic/action.md)
- [OLED Display](./oled/index.md)
- [I2C](./oled/i2c.md)
- [Hello World](./oled/hello-world.md)
- [Hello World](./oled/hello-oled.md)
- [Ferris](./oled/ferris.md)

- [Resources](./resources.md)
Binary file added src/oled/assets/ferris.bmp
Binary file not shown.
Binary file added src/oled/assets/rust.raw
Binary file not shown.
34 changes: 33 additions & 1 deletion src/oled/ferris.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
# Ferris on OLED

//TODO:
In this task, we will display the `ferris.bmp`([Download](./assets/ferris.bmp) and put it in the project folder) file on the OLED screen.

<img style="display: block; margin: auto;" alt="pico2" src="./assets/ferris.bmp"/>

Follow the same instructions as in the "Hello Rust" program, with just a few modifications.

First, we need to add the tinybmp crate to handle BMP file loading. Use the following Cargo command to include it in your project:
```sh
cargo add [email protected]
```

## Additional imports
```rust
use embedded_graphics::image::Image;
use tinybmp::Bmp;
```

## Difference

After initializing the display, we will load the ferris.bmp file using the tinybmp crate, and then we will draw the image.
```rust
let bmp = Bmp::from_slice(include_bytes!("../ferris.bmp")).unwrap();
let im = Image::new(&bmp, Point::new(32, 0));
im.draw(&mut display).unwrap();
```

## Clone the existing project
You can clone (or refer) project I created and navigate to the `ferris-oled` folder.

```sh
git clone https://github.com/ImplFerris/pico2-projects
cd pico2-projects/ferris-oled
```
140 changes: 140 additions & 0 deletions src/oled/hello-oled.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Hello Rust on OLED

We will create a simple program to display "Hello, Rust" in the OLED display.

## Generating From template

Refer to the [Template section](../cargo-generate.md) for details and instructions.

To generate the project, run:

```sh
cargo generate --git https://github.com/ImplFerris/pico2-template.git
```
When prompted, choose a name for your project-let's go with "oh-led". Don't forget to select `rp-hal` as the HAL.

Then, navigate into the project folder:
```sh
cd PROJECT_NAME
# For example, if you named your project "oh-led":
# cd oh-led
```

### Add Additional Dependencies

Since we are using the SSD1306 OLED display, we need to include the SSD1306 driver. To add this dependency, use the following Cargo command:
```sh
cargo add [email protected]
```

We will use the embedded_graphics crate to handle graphical rendering on the OLED display, to draw images, shapes, and text.
```sh
cargo add [email protected]
```

## Code

### Additional imports
In addition to the imports from the template, you'll need the following additional dependencies for this task.
```rust
use hal::fugit::RateExtU32;
use hal::gpio::{FunctionI2C, Pin};
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
use embedded_graphics::prelude::*;
use embedded_graphics::mono_font::ascii::FONT_6X10;
use embedded_graphics::mono_font::MonoTextStyleBuilder;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::text::{Baseline, Text};
```

### Pin Configuration
We start by configuring the GPIO pins for the I2C communication. In this case, GPIO18 is set as the SDA pin, and GPIO19 is set as the SCL pin. We then configure the I2C peripheral to work in master mode.

```rust
// Configure two pins as being I²C, not GPIO
let sda_pin: Pin<_, FunctionI2C, _> = pins.gpio18.reconfigure();
let scl_pin: Pin<_, FunctionI2C, _> = pins.gpio19.reconfigure();

let i2c = hal::I2C::i2c1(
pac.I2C1,
sda_pin,i2c1
scl_pin,
400.kHz(),
&mut pac.RESETS,
&clocks.system_clock,
);
```

### Prepare Display
We create an interface for the OLED display using the I2C.

```rust
//helper struct is provided by the ssd1306 crate
let interface = I2CDisplayInterface::new(i2c);
// initialize the display
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
.into_buffered_graphics_mode();
display.init().unwrap();
```

### Set Text Style and Draw
Next, we define the text style and use it to display "Hello Rust" on the screen:
```rust
// Embedded graphics
let text_style = MonoTextStyleBuilder::new()
.font(&FONT_6X10)
.text_color(BinaryColor::On)
.build();

Text::with_baseline("Hello, Rust!", Point::new(0, 16), text_style, Baseline::Top)
.draw(&mut display)
.unwrap();
```

### Write out data to a display
```rust
display.flush().unwrap();
```

## Full logic
```rust
let sda_pin: Pin<_, FunctionI2C, _> = pins.gpio18.reconfigure();
let scl_pin: Pin<_, FunctionI2C, _> = pins.gpio19.reconfigure();

let i2c = hal::I2C::i2c1(
pac.I2C1,
sda_pin,
scl_pin,
400.kHz(),
&mut pac.RESETS,
&clocks.system_clock,
);

let interface = I2CDisplayInterface::new(i2c);

let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
.into_buffered_graphics_mode();

display.init().unwrap();
let text_style = MonoTextStyleBuilder::new()
.font(&FONT_6X10)
.text_color(BinaryColor::On)
.build();

Text::with_baseline("Hello, Rust!", Point::new(0, 16), text_style, Baseline::Top)
.draw(&mut display)
.unwrap();

display.flush().unwrap();
loop {
timer.delay_ms(500);
}
```

## Clone the existing project
You can clone (or refer) project I created and navigate to the `hello-oled` folder.

```sh
git clone https://github.com/ImplFerris/pico2-projects
cd pico2-projects/hello-oled
```
3 changes: 0 additions & 3 deletions src/oled/hello-world.md

This file was deleted.

29 changes: 28 additions & 1 deletion src/oled/i2c.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
# I2C

//TODO:
I²C, also known as I2C or IIC (Inter-Integrated Circuit), is a communication protocol widely used to link microcontrollers with devices like sensors, displays, and other integrated circuits. This protocol is also called the Two-Wire Interface (TWI).

- Two Wires: Only 2 lines, SDA (Serial Data) and SCL (Serial Clock), are used to transfer data.
- The SDA line is used by both the master and slave to send and receive data
- The SCL line carries the clock signal

- Multi-Device Support: I2C allows multiple slave devices to be connected to a single master, and it also supports multiple masters.

- The master is responsible for generating the clock and controlling the transfer of data, while the slave responds by either transmitting or receiving data from the master.

## RP2350's I2C
The RP2350 has 2 identical I2C controllers, each connected to specific GPIO pins on the Raspberry Pi Pico.

| I2C Controller | GPIO Pins |
|----------------|---------------------------------|
| I2C0 – SDA | GP0, GP4, GP8, GP12, GP16, GP20 |
| I2C0 – SCL | GP1, GP5, GP9, GP13, GP17, GP21 |
| I2C1 – SDA | GP2, GP6, GP10, GP14, GP18, GP26|
| I2C1 – SCL | GP3, GP7, GP11, GP15, GP19, GP27|

<br/>
<a href="../images/pico2-board.png"><img style="display: block; margin: auto;" alt="pico2" src="../images/pico2-board.png"/></a>

## Resources
- [Basics of the I2C Communication Protocol](https://www.circuitbasics.com/basics-of-the-i2c-communication-protocol/)
- [A Basic Guide to I2C](https://www.ti.com/lit/an/sbaa565/sbaa565.pdf)
- [I2C in a Nutshell](https://interrupt.memfault.com/blog/i2c-in-a-nutshell)
- [I2C](https://learn.sparkfun.com/tutorials/i2c/all)

0 comments on commit 0c5cbd0

Please sign in to comment.