Skip to content

Commit

Permalink
intro expanded
Browse files Browse the repository at this point in the history
  • Loading branch information
ImplFerris committed Dec 24, 2024
1 parent 48b442a commit d66881e
Show file tree
Hide file tree
Showing 21 changed files with 403 additions and 66 deletions.
12 changes: 9 additions & 3 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# Summary

- [Introduction](./index.md)
- [ESP32 Family](./esp32-family.md)
- [ESP32 Family](./esp32-intro/esp32-family.md)
- [Pinout Diagram](./esp32-intro/pinout.md)
- [Dev Environment](./dev-env.md)
- [Quick Start](./quick-start.md)
- [Async and Embassy](./embassy.md)
- [Pinout Diagram](./pinout.md)
<!-- - [Dimming LED](./dimming-led/index.md) -->
- [Core Concepts](./core-concepts/index.md)
- [Voltage Divider](./core-concepts/voltage-divider.md)
- [ADC](./core-concepts/adc.md)
- [PWM](./core-concepts/pwm/index.md)
- [no_std, no_main in Rust](./core-concepts/no-std-main.md)
- [Dimming LED](./dimming-led/index.md)
- [LED PWM Controller](./core-concepts/pwm/led-pwm-controller.md)
82 changes: 82 additions & 0 deletions src/core-concepts/adc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# ADC (Analog to Digital Converter)

An Analog-to-Digital Converter (ADC) is a device used to convert analog signals (continuous signals like sound, light, or temperature) into digital signals (discrete values, typically represented as 1s and 0s). This conversion is necessary for digital systems like microcontrollers (e.g., Raspberry Pi, Arduino) to interact with the real world. For example, sensors that measure temperature or sound produce analog signals, which need to be converted into digital format for processing by digital devices.

<img style="display: block; margin: auto;" alt="ADC" src="./images/adc.jpg"/>

## ADC Resolution
The resolution of an ADC refers to how precisely the ADC can measure an analog signal. It is expressed in bits, and the higher the resolution, the more precise the measurements.

- 8-bit ADC produces digital values between 0 and 255.
- 10-bit ADC produces digital values between 0 and 1023.
- 12-bit ADC produces digital values between 0 and 4095.

The resolution of the ADC can be expressed as the following formula:
\\[
\text{Resolution} = \frac{\text{Vref}}{2^{\text{bits}} - 1}
\\]

## ESP32
The ESP32 has 12-bit Analogue to Digital Converter (ADC). So, it provides values ranging from 0 to 4095 (4096 possible values)

\\[
\text{Resolution} = \frac{3.3V}{2^{12} - 1} = \frac{3.3V}{4095} \approx 0.000805 \text{V} \approx 0.8 \text{mV}
\\]

## Pins
//TODO: details of ESP32 ADC Pins

## ADC Value and LDR Resistance in a Voltage Divider
In a voltage divider with an LDR and a fixed resistor, the output voltage \\( V_{\text{out}} \\) is given by:

\\[
V_{\text{out}} = V_{\text{in}} \times \frac{R_{\text{LDR}}}{R_{\text{LDR}} + R_{\text{fixed}}}
\\]

It is same formula as explained in the previous chapter, just replaced the \\({R_2}\\) with \\({R_{\text{LDR}}}\\) and \\({R_1}\\) with \\({R_{\text{fixed}}}\\)

- **Bright light** (low LDR resistance): \\( V_{\text{out}} \\) decreases, resulting in a lower ADC value.
- **Dim light** (high LDR resistance): \\( V_{\text{out}} \\) increases, leading to a higher ADC value.

## Example ADC value calculation:

**Bright light**:

Let's say the Resistence value of LDR is \\(1k\Omega\\) in the bright light (and we have \\(10k\Omega\\) fixed resistor).

\\[
V_{\text{out}} = 3.3V \times \frac{1k\Omega}{1k\Omega + 10k\Omega} \approx 0.3V
\\]

The ADC value is calculated as:
\\[
\text{ADC value} = \left( \frac{V_{\text{out}}}{V_{\text{ref}}} \right) \times (2^{12} - 1) \approx \left( \frac{0.3}{3.3} \right) \times 4095 \approx 372
\\]

**Darkness**:

Let's say the Resistence value of LDR is \\(140k\Omega \\) in very low light.

\\[
V_{\text{out}} = 3.3V \times \frac{140k\Omega}{140k\Omega + 10k\Omega} \approx 3.08V
\\]

The ADC value is calculated as:
\\[
\text{ADC value} = \left( \frac{V_{\text{out}}}{V_{\text{ref}}} \right) \times (2^{12} - 1) \approx \left( \frac{3.08}{3.3} \right) \times 4095 = 3822
\\]

### **Converting ADC value back to voltage**:

Now, if we want to convert the ADC value back to the input voltage, we can multiply the ADC value by the resolution (0.8mV).

For example, let's take an ADC value of 3822:

\\[
\text{Voltage} = 3822 \times 0.8mV = 3057.6mV \approx 3.06V
\\]


## Reference
- [What is Analog to Digital Converter & Its Working](https://www.elprocus.com/analog-to-digital-converter/)

Binary file added src/core-concepts/images/adc.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/core-concepts/images/led-pwm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/core-concepts/images/pwm-duty-cycle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/core-concepts/images/voltage-divider.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/core-concepts/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Core concepts

This section primarily covers theoretical concepts. Feel free to skip it and dive into the exercises instead. As you work through the exercises related to each concept, we'll link back to the theory. This approach may help you understand the material better by showing you exactly where and why these concepts are needed in practice.

49 changes: 49 additions & 0 deletions src/core-concepts/no-std-main.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# No Standard and Main in Rust

If you haven't read "The Embedded Rust Book" yet, I highly recommend you to check it out.
[https://docs.rust-embedded.org/book/intro/index.html](https://docs.rust-embedded.org/book/intro/index.html)

## #![no_std]
The `#![no_std]` attribute disables the use of the standard library (std). This is necessary most of the times for embedded systems development, where the environment typically lacks many of the resources (like an operating system, file system, or heap allocation) that the standard library assumes are available.

**Related Resources:**
- [Rust official doc](https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute)
- [The Embedded Rust Book](https://docs.rust-embedded.org/book/intro/no-std.html)
- [Writing an OS in Rust Book](https://os.phil-opp.com/freestanding-rust-binary/#the-no-std-attribute)

## #![no_main]
The `#![no_main]` attribute is to indicate that the program won't use the standard entry point (fn main). Instead, it provides a custom entry point, usually required when working with embedded systems where the runtime environment is minimal or non-existent.

**Related Resources:**
- [Rust official doc](https://doc.rust-lang.org/reference/crates-and-source-files.html?highlight=no_main#the-no_main-attribute)
- [Writing an OS in Rust Book](https://os.phil-opp.com/freestanding-rust-binary/#overwriting-the-entry-point)


## Panic Handler
A panic handler is a function in Rust that defines what happens when your program encounters a panic. In environments without the standard library (when using no_std attribute), you need to create this function yourself using the #[panic_handler] attribute. This function must follow a specific format and can only appear once in your program. It provides details about the error, such as where it happened and why. By setting up a panic handler, you can choose how to respond to errors, like logging them for later review or stopping the program completely.

You don't have to define your own panic handler function; you can use existing crates such as panic_halt or panic_probe instead.

For example, we used the panic_halt crate to halt execution when a panic occurs.
```rust
use panic_halt as _;
```
The program will stop and remain in this infinite loop whenever a panic occurs.

In fact, the [panic_halt crate's code](https://github.com/korken89/panic-halt/blob/master/src/lib.rs) implements a simple panic handler, which looks like this:
```rust
use core::panic::PanicInfo;
use core::sync::atomic::{self, Ordering};

#[inline(never)]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {
atomic::compiler_fence(Ordering::SeqCst);
}
}
```

**Related Resources:**
- [Rust official doc](https://doc.rust-lang.org/nomicon/panic-handler.html)
- [The Embedded Rust Book](https://docs.rust-embedded.org/book/start/panicking.html)
62 changes: 62 additions & 0 deletions src/core-concepts/pwm/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

# Pulse Width Modulation (PWM)

In this section, we will explore what is PWM and why we need it.

## Digital vs Analog
In a digital circuit, signals are either high (such as 5V or 3.3V) or low (0V), with no in-between values. These two distinct states make digital signals ideal for computers and digital devices, as they're easy to store, read, and transmit without losing accuracy.

Analog signals, however, can vary continuously within a range, allowing for any value between a High and Low voltage. This smooth variation is valuable for applications requiring fine control, such as adjusting audio volume or light brightness.

Devices like servo motors and LEDs(for dimming effect) often need gradual, precise control over voltage, which analog signals provide through their continuous range.

Microcontrollers use PWM to bridge this gap.

## What is PWM?
PWM stands for **Pulse Width Modulation**, creates an analog-like signal by rapidly pulsing a digital signal on and off. The average output voltage, controlled by adjusting the pulse's high duration or "duty cycle," can simulate a continuous analog level.

<img style="display: block; margin: auto;" alt="LED PWM" src="../images/led-pwm.jpg" />


The **duty cycle** of the signal determines how long it stays on compared to how long it stays off.

- **Duty Cycle**:
The percentage of time the signal is on during one cycle.
- For example:
- 100% duty cycle means the signal is always on.
- 50% duty cycle means the signal is on half the time and off half the time.
- 0% duty cycle means the signal is always off.
<img style="display: block; margin: auto;" alt="Duty Cycle" src="../images/pwm-duty-cycle.png" />
<span style="text-align: center;display: block; margin: auto; font-size: 12px;">Image Credit: Wikipedia</span>

## Period and Frequency
Period is the total time for one on-off cycle to complete.

The frequency of a PWM signal is the number of cycles it completes in one second, measured in Hertz (Hz). Frequency is the inverse of the period:

\\[
\text{Frequency (Hz)} = \\frac{1}{\text{Period (s)}}
\\]

So if the period is 1 second, then the frequency will be 1HZ.

\\[
1 \text{Hz} = \\frac{1 \text{ cycle}}{1 \text{ second}} = \\frac{1}{1 \text{ s}}
\\]

For example, if the period is 20ms(0.02s), the frequency will be 50Hz.

\\[
\text{Frequency} = \\frac{1}{20 \text{ ms}} = \\frac{1}{0.02 \text{ s}} = 50 \text{ Hz}
\\]



**Calculating Cycle count from Frequency per second**

The Formula to calculate cycle count:
\\[
\text{Cycle Count} = \text{Frequency (Hz)} \\times \text{Total Time (seconds)}
\\]

If a PWM signal has a frequency of 50Hz, it means it completes 50 cycles in one second.
1 change: 1 addition & 0 deletions src/core-concepts/pwm/led-pwm-controller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# LED PWM Controller
12 changes: 12 additions & 0 deletions src/core-concepts/voltage-divider-ldr.circuitjs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
$ 1 0.000005 10.20027730826997 63 10 62 5e-11
v 240 400 240 80 0 0 40 3.3 0 0 0.5
w 240 80 368 80 0
r 368 80 368 240 0 10000
w 240 400 368 400 0
O 368 240 432 240 1 0
x 378 144 393 147 4 12 R1
x 377 305 392 308 4 12 R2
x 199 219 227 222 4 14 3.3V
x 209 201 223 204 4 10 Vin
x 424 227 444 230 4 10 Vout
374 368 240 368 400 0 0.0001 Light\sBrightness
12 changes: 12 additions & 0 deletions src/core-concepts/voltage-divider.circuitjs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
$ 1 0.000005 10.20027730826997 63 10 62 5e-11
v 240 400 240 80 0 0 40 3.3 0 0 0.5
w 240 80 368 80 0
r 368 80 368 240 0 10000
w 240 400 368 400 0
O 368 240 432 240 1 0
x 378 144 393 147 4 12 R1
x 377 305 392 308 4 12 R2
r 368 400 368 240 0 10000
x 199 219 227 222 4 14 3.3V
x 209 201 223 204 4 10 Vin
x 424 227 444 230 4 10 Vout
53 changes: 53 additions & 0 deletions src/core-concepts/voltage-divider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Voltage Divider

A **voltage divider** is a simple circuit that reduces an input voltage \\( V_{in} \\) to a lower output voltage \\( V_{out} \\) using two series resistors. The resistor connected to the input voltage \\( V_{in} \\) is called \\( R_{1} \\), and the other resistor is \\( R_{2} \\). The output voltage \\( V_{out} \\) is taken from the junction between \\( R_{1} \\) and \\( R_{2} \\), producing a fraction of \\( V_{in} \\).

## Circuit

<img style="display: block; margin: auto;" alt="Voltage Divider" src="./images/voltage-divider.png"/>

The output voltage (V<sub>out</sub>) is calculated using this formula:

\\[
V_{out} = V_{in} \times \frac{R_2}{R_1 + R_2}
\\]

### Example Calculation for \\( V_{out} \\)

Given:
- \\( V_{in} = 3.3V \\)
- \\( R_1 = 10 k\Omega \\)
- \\( R_2 = 10 k\Omega \\)

Substitute the values:

\\[
V_{out} = 3.3V \times \frac{10 k\Omega}{10 k\Omega + 10 k\Omega} = 3.3V \times \frac{10}{20} = 3.3V \times 0.5 = 1.65V
\\]


The output voltage \\( V_{out} \\) is 1.65V.


```rust,editable
fn main() {
// You can edit the code
// You can modify values and run the code
let vin: f64 = 3.3;
let r1: f64 = 10000.0;
let r2: f64 = 10000.0;
let vout = vin * (r2 / (r1 + r2));
println!("The output voltage Vout is: {:.2} V", vout);
}
```

## Use cases

Voltage dividers are used in applications like potentiometers, where the resistance changes as the knob is rotated, adjusting the output voltage. They are also used to measure resistive sensors such as light sensors and thermistors, where a known voltage is applied, and the microcontroller reads the voltage at the center node to determine sensor values like temperature.


## Simulator

I used the website [https://www.falstad.com/circuit/e-voltdivide.html](https://www.falstad.com/circuit/e-voltdivide.html) to create this diagram. It's a great tool for drawing circuits. You can download the file I created, [`voltage-divider.circuitjs.txt`](./voltage-divider.circuitjs.txt), and import it to experiment with the circuit.
2 changes: 1 addition & 1 deletion src/dimming-led/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Dimming LED

In this exercise, we'll dim an external LED using Pulse Width Modulation (PWM), which will be explained in the next chapter. Essentially, we control the LED's brightness by adjusting the duty cycle (explained in the PWM section), which varies at regular intervals to create a dimming effect.
In this exercise, we'll dim an external LED using Pulse Width Modulation (PWM), which will be explained in the next chapter.

## Hardware Requirements

Expand Down
8 changes: 8 additions & 0 deletions src/dimming-led/led-pwm-controller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# LED PWM

The ESP32 has LED PWM Controller(LEDC) that generates PWM signals for controlling LEDs(example, dimming effect). However, its functionality isn't limited to LEDs;you can use it for other applications as well. If you are not familiar with PWM(Pulse Width Modulation), i recommend you to check the PWM section [here](../core-concepts/pwm.md).

The LEDC includes 16 independent PWM generators and supports a maximum PWM duty cycle resolution of 20 bits. The 16 PWM channels further classified into two types: 8 high speed channel and 8 low speed channels.

The PWM controller can automatically increase or decrease the duty cycle gradually, allowing for smooth fades without using the processor. For more details, refer to page 390 of the [ESP32 Technical Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf#ledpwm).

60 changes: 0 additions & 60 deletions src/esp32-family.md

This file was deleted.

Loading

0 comments on commit d66881e

Please sign in to comment.