Skip to content

Commit

Permalink
LED Fader section
Browse files Browse the repository at this point in the history
  • Loading branch information
ImplFerris committed Dec 26, 2024
1 parent 2be4a37 commit 8589876
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 17 deletions.
4 changes: 3 additions & 1 deletion src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@
- [PWM in Depth](./core-concepts/pwm/pwm-in-depth.md)
- [LED PWM Controller](./core-concepts/pwm/led-pwm-controller.md)
- [no_std, no_main in Rust](./core-concepts/no-std-main.md)
- [Dimming LED](./dimming-led/index.md)
- [Dimming LED](./led/index.md)
- [Code](./led/code.md)
- [External LED](./led/external-led.md)
3 changes: 3 additions & 0 deletions src/core-concepts/pwm/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ For example:
- 0% duty cycle means the signal is always off.




Here is the interactive simulation. Use the sliders to adjust the duty cycle and frequency, and watch how the pulse width and LED brightness change. The upper part of the square wave represents when the signal is high (on). The lower part represents when the signal is low(off)

<canvas id="pwmCanvas" width="800" height="200"></canvas>
Expand Down Expand Up @@ -150,6 +152,7 @@ The Formula to calculate cycle count:

If a PWM signal has a frequency of 50Hz, it means it completes 50 cycles in one second.

In the next chapter, we will go in depth into the PWM and timer.

<script>
const pwmCanvas = document.getElementById('pwmCanvas');
Expand Down
4 changes: 2 additions & 2 deletions src/core-concepts/pwm/led-pwm-controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ For more details, refer to page 390 of the [ESP32 Technical Reference Manual](ht

## Calculating PWM Duty Resolution

When working with PWM signals in embedded systems, one important aspect to understand is how to calculate the **duty resolution** based on the clock frequency and division factor. The duty resolution determines how finely you can control the duty cycle of a PWM signal.

In the ESP-HAL, we need to specify both the duty resolution and the frequency when configuring the timer object. Therefore, it's important to understand how to calculate the duty resolution from a desired frequency and how to determine the frequency based on a given duty resolution.
These are the formulas taken from the ESP32 technical reference manual but the variable names are simplified.

### Formula for PWM Signal Frequency
Expand Down
14 changes: 0 additions & 14 deletions src/dimming-led/index.md

This file was deleted.

2 changes: 2 additions & 0 deletions src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ In this book, we use the ESP32 and program it in Rust to explore various excitin
## Prerequisites
If you haven't already read the ["The Rust on ESP Book"](https://docs.esp-rs.org/book/introduction.html), I highly recommend doing so first. While this book will cover some aspects of setting up the development environment and basic concepts, it will not go into as much detail to avoid unnecessary repetition, as these topics are already thoroughly explained in the official book.

I also recommend you to read ["The Embedded Rust book"](https://docs.rust-embedded.org/book/intro/index.html) - An introductory book about using the Rust on "Bare Metal" embedded systems.

## Meet the Hardware
We will be using one of the development board "ESP32 DevKit V1", which comes with built-in Wi-Fi and Bluetooth capabilities, along with an integrated RF module
<a href ="./images/esp32-devkitv1.jpg"><img style="display: block; margin: auto;width:300px;" src="./images/esp32-devkitv1.jpg"/></a>
Expand Down
135 changes: 135 additions & 0 deletions src/led/code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
## Code

Now comes the fun part; let's dive into the coding!

Let's start by initializing the peripherals with the default configuration. This function configures the CPU clock and watchdog, and then returns the instance of the peripherals.

```rust
let peripherals = esp_hal::init(esp_hal::Config::default());
```

Next, we take our desired GPIO from the peripherals instance. In this case, we're turning on the onboard LED of the Devkit, which is connected to GPIO 2.

```rust
let led = peripherals.GPIO2;
```

### PWM configuration
In this exercise, we will be using the low-speed PWM channel. First, we need to set the clock source. The esp-hal library defines the `LSGlobalClkSource` enum for the low-speed clock source, which currently has only one value: `APBClk`.

```rust
ledc.set_global_slow_clock(LSGlobalClkSource::APBClk);
```

Next, we configure the timer. Since we are using the low-speed PWM channel, we obviously need to use the low-speed timer. We also have to specify which low-speed timer to use (from 0 to 3).

```rust
let mut lstimer0 = ledc.timer::<LowSpeed>(timer::Number::Timer0);
```

We need to do a few more configurations before using the timer. We'll set the frequency to 24 kHz. For this frequency with the APB clock, the formula gives a maximum resolution of 12 bits and a minimum resolution of 2 bits. In the esp-hal, a 5-bit PWM resolution is used for this frequency, and we will use the same.

```rust
lstimer0.configure(timer::config::Config {
duty: timer::config::Duty::Duty5Bit,
clock_source: timer::LSClockSource::APBClk,
frequency: 24.kHz(),
})
.unwrap();
```

### PWM Channels
Next, we configure the PWM channel. We'll use channel0 and set it up with the selected timer and initial duty percentage "10%". Additionally, we'll set the pin configuration as PushPull.

```rust
let mut channel0 = ledc.channel(channel::Number::Channel0, led);
channel0.configure(channel::config::Config {
timer: &lstimer0,
duty_pct: 10,
pin_config: channel::config::PinConfig::PushPull,
})
.unwrap();
```

### Fading

The esp-hal has a function called start_duty_fade, which makes our job easier. Otherwise, we would have to manually increment and decrement the duty cycle in a loop at regular intervals. This function gradually changes from one duty cycle percentage to another. It also accepts a third parameter, which specifies how much time it should take to transition from one duty cycle to another.

```rust
channel0.start_duty_fade(0, 100, 1000).unwrap();
```

We will run this in a loop and use another function provided by the HAL, is_duty_fade_running; It returns boolean value whether the duty fade is complete or not.

```rust
while channel0.is_duty_fade_running() {}
```

## The full code

```rust
#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_hal::{
ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
LSGlobalClkSource, Ledc, LowSpeed,
},
prelude::*,
};

#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());

let led = peripherals.GPIO2;
// let led = peripherals.GPIO5;

let mut ledc = Ledc::new(peripherals.LEDC);
ledc.set_global_slow_clock(LSGlobalClkSource::APBClk);

let mut lstimer0 = ledc.timer::<LowSpeed>(timer::Number::Timer0);
lstimer0
.configure(timer::config::Config {
duty: timer::config::Duty::Duty5Bit,
clock_source: timer::LSClockSource::APBClk,
frequency: 24.kHz(),
})
.unwrap();

let mut channel0 = ledc.channel(channel::Number::Channel0, led);
channel0
.configure(channel::config::Config {
timer: &lstimer0,
duty_pct: 10,
pin_config: channel::config::PinConfig::PushPull,
})
.unwrap();

loop {
channel0.start_duty_fade(0, 100, 1000).unwrap();
while channel0.is_duty_fade_running() {}
channel0.start_duty_fade(100, 0, 1000).unwrap();
while channel0.is_duty_fade_running() {}
}
}
```


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

```sh
git clone https://github.com/ImplFerris/esp32-projects
cd esp32-projects/led-fader
```

## Flashing
Once you flash the code into the ESP32, you should see the fading effect on the onboard LED.

```rust
cargo run --release
```
27 changes: 27 additions & 0 deletions src/led/external-led.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Using external LED

You can do the same fading effect with external LED.

## Hardware Requirements

- External LED
- Resistor (330 Ohms)
- Jumper wires (optional)
- Breadboard (optional) - You might need two breadboards to fit the ESP32 devkit properly, as it's quite wide. I bought two small breadboards and placed one side of the ESP32 on each.


## Circuit
- Connect the anode (longer leg) of the external LED to ESP32's GPIO 5 through the 330-ohm resistor
- Connect the cathode (shorter leg) of the LED to the ground (GND) pin of the ESP32
<br/><br/>
<img style="display: block; margin: auto;" src="./images/esp32-external-led-circuit.jpg"/>


## Code changes

In the code, all you have to do is change the GPIO number from 2 to 5.

```rust
let led = peripherals.GPIO5;
```

Binary file added src/led/images/esp32-external-led-circuit.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/led/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# LED Fading effect

In this section, we will learn how to create a fading effect(i.e. reducing and increasing the brightness) for an LED using the Raspberry Pi Pico 2. First, we will fade the onboard LED, which is connected to GPIO 2.

To make the fading effect, we use a technique called PWM (Pulse Width Modulation). You can refer to the intro to the PWM section [here](../core-concepts/pwm/index.md).

We will gradually increment the PWM's duty cycle to increase the brightness, then we gradually decrement the PWM duty cycle to reduce the brightness of the LED. This effectively creates the fading effect on the LED

## The Eye
"
Come in close... Closer...

Because the more you think you see... The easier it’ll be to fool you...

Because, what is seeing?.... You're looking but what you're really doing is filtering, interpreting, searching for meaning...
"

Now, here's the cool part: when this switching happens super quickly, our eyes can't keep up. Instead of seeing the blinking, it just looks like the brightness changes! The longer the LED stays ON, the brighter it seems, and the shorter it's ON, the dimmer it looks. It's like tricking your brain into thinking the LED is smoothly dimming or brightening. PWM: the magician of electronics!

0 comments on commit 8589876

Please sign in to comment.