# LED Control

## Lab 6: Hardware LED Control

### 1. โครงสร้างภาพรวมของ Lab

#### Why? - ทำไมต้องเรียนรู้เรื่องนี้

นี่คือ Lab แรกที่เชื่อมต่อ **LVGL UI** เข้ากับ **Hardware จริง** บนบอร์ด PSoC Edge E84:

* **UI-to-Hardware Bridge**: ควบคุม LED จริงจากหน้าจอสัมผัส
* **GPIO Output**: เข้าใจการส่งสัญญาณออกทาง Digital Pin
* **PWM Dimming**: ควบคุมความสว่าง LED ด้วย Pulse Width Modulation
* **Industrial Application**: พื้นฐานของ HMI (Human-Machine Interface) ในโรงงาน

#### What? - จะได้เรียนรู้อะไร

1. **GPIO Initialization**: เรียก `aic_gpio_init()` ก่อนใช้งาน GPIO
2. **LED On/Off Control**: ใช้ `aic_gpio_led_set()` ควบคุม 3 สี (Red, Green, Blue)
3. **PWM Brightness**: ใช้ `aic_gpio_pwm_set_duty()` ปรับความสว่าง Blue LED
4. **LVGL Event → Hardware Action**: เมื่อ user กด Switch บนจอ → LED บนบอร์ดติด/ดับ

#### How? - ทำอย่างไร

1. Initialize GPIO subsystem ด้วย `aic_gpio_init()`
2. สร้าง LVGL Switch widgets สำหรับ LED แต่ละสี
3. สร้าง LVGL Slider สำหรับ PWM brightness
4. ใน Event Callback ให้เรียก `aic_gpio_led_set()` ควบคุม LED จริง

<figure><img src="https://1856353139-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MClo3nC-1US0rbK8Qau%2Fuploads%2FPkJvk5iCVoV24LQmxymm%2Fweek3_ex3_led_control.gif?alt=media&#x26;token=638cf559-f005-4fc2-b828-c970c10d8072" alt=""><figcaption></figcaption></figure>

***

### ขั้นตอนการดาวโหลดจาก Github Repo และรันโปรแกรม Button Demo

{% embed url="<https://www.youtube.com/watch?v=hO5Z_OBwA6o>" fullWidth="true" %}

> **หมายเหตุ:** GitHub Repo --> <https://github.com/Advance-Innovation-Centre-AIC/psoc-e84-e2-lvgl-aic-eec>

***

## ดาวน์โหลด GitHub Repo&#x20;

{% embed url="<https://github.com/Advance-Innovation-Centre-AIC/psoc-e84-e2-lvgl-aic-eec>" %}

### 2. หลักการทำงาน (Technical Principles)

#### 2.1 LED Hardware Configuration

```
+-------------------------------------------------------------+
|             PSoC Edge E84 LED Configuration                  |
+-------------------------------------------------------------+
|                                                              |
|   LED           Pin       PWM Support    Control Method      |
|   ---------------------------------------------------------- |
|   Red (LED1)    P16_7     No  (GPIO)     ON/OFF only         |
|   Green (LED2)  P16_6     No  (GPIO)     ON/OFF only         |
|   Blue (LED3)   P16_5     Yes (TCPWM0)   Dimming 0-100%     |
|                                                              |
|   IMPORTANT: Only Blue LED supports PWM brightness control!  |
|                                                              |
+-------------------------------------------------------------+
```

#### 2.2 GPIO API Flow

```
+-------------------------------------------------------------+
|                    GPIO API FLOW                             |
+-------------------------------------------------------------+
|                                                              |
|   +---------------------+                                    |
|   |  aic_gpio_init()    |  <-- Call ONCE at startup          |
|   +----------+----------+                                    |
|              |                                               |
|   +----------+----------+                                    |
|   |                     |                                    |
|   v                     v                                    |
|   GPIO Control          PWM Control                          |
|   (Red/Green/Blue)      (Blue only)                          |
|   |                     |                                    |
|   v                     v                                    |
|   aic_gpio_led_set()    aic_gpio_pwm_init(AIC_LED_BLUE)      |
|   (led, true/false)     |                                    |
|                         v                                    |
|                         aic_gpio_pwm_set_duty()              |
|                         (AIC_LED_BLUE, 0-100)                |
|                                                              |
+-------------------------------------------------------------+
```

#### 2.3 LVGL Event -> Hardware Action

```
+-------------------------------------------------------------+
|              UI EVENT -> HARDWARE CONTROL                    |
+-------------------------------------------------------------+
|                                                              |
|   [LVGL Switch ON]                                           |
|        |                                                     |
|        v                                                     |
|   event_cb() called                                          |
|        |                                                     |
|        +---> lv_obj_has_state(sw, LV_STATE_CHECKED)          |
|        |         |                                           |
|        |    true |          false                            |
|        |         v              v                            |
|        |   aic_gpio_led_set    aic_gpio_led_set              |
|        |   (LED_RED, true)     (LED_RED, false)              |
|        |                                                     |
|   [LVGL Slider Changed]                                      |
|        |                                                     |
|        v                                                     |
|   slider_cb() called                                         |
|        |                                                     |
|        +---> duty = lv_slider_get_value(slider)              |
|        |                                                     |
|        +---> aic_gpio_pwm_set_duty(AIC_LED_BLUE, duty)       |
|                                                              |
+-------------------------------------------------------------+
```

***

### 3. ฟังก์ชันสำคัญ (API Reference)

#### 3.1 Hardware GPIO API (aic-eec.h)

<table><thead><tr><th width="298.5703125">Function</th><th>Description</th><th>Parameters</th></tr></thead><tbody><tr><td><code>aic_gpio_init()</code></td><td>Initialize GPIO subsystem</td><td>ไม่มี</td></tr><tr><td><code>aic_gpio_led_set(led, state)</code></td><td>ตั้งค่า LED ON/OFF</td><td><code>led</code>: AIC_LED_RED/GREEN/BLUE, <code>state</code>: true/false</td></tr><tr><td><code>aic_gpio_pwm_init(led)</code></td><td>Initialize PWM สำหรับ LED</td><td><code>led</code>: AIC_LED_BLUE เท่านั้น</td></tr><tr><td><code>aic_gpio_pwm_set_duty(led, duty)</code></td><td>ตั้งค่าความสว่าง</td><td><code>led</code>: AIC_LED_BLUE, <code>duty</code>: 0-100</td></tr></tbody></table>

#### 3.2 LED Type Constants

```c
AIC_LED_RED        // LED แดง  - GPIO ON/OFF only
AIC_LED_GREEN      // LED เขียว - GPIO ON/OFF only
AIC_LED_BLUE       // LED น้ำเงิน - GPIO + PWM dimming
```

#### 3.3 LVGL Functions ที่ใช้ในบทนี้

| Function                                  | Description                         |
| ----------------------------------------- | ----------------------------------- |
| `lv_switch_create(parent)`                | สร้าง Switch widget                 |
| `lv_slider_create(parent)`                | สร้าง Slider widget                 |
| `lv_slider_set_range(slider, min, max)`   | กำหนดช่วงค่า Slider                 |
| `lv_slider_get_value(slider)`             | อ่านค่าปัจจุบันของ Slider           |
| `lv_led_create(parent)`                   | สร้าง LED indicator widget          |
| `lv_led_on(led)` / `lv_led_off(led)`      | เปิด/ปิด LED indicator              |
| `lv_led_set_brightness(led, bright)`      | ตั้งความสว่าง LED indicator (0-255) |
| `lv_led_set_color(led, color)`            | ตั้งสี LED indicator                |
| `lv_obj_has_state(obj, LV_STATE_CHECKED)` | ตรวจสอบสถานะ Switch                 |

***

### 4. โค้ดตัวอย่าง (Code Examples)

#### 4.1 Minimal Example: Single LED Toggle

```c
#include "aic-eec.h"

/* ตัวแปร global สำหรับ UI widgets */
static lv_obj_t * led_indicator;

/* Callback เมื่อ Switch เปลี่ยนสถานะ */
static void red_switch_cb(lv_event_t * e)
{
    if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;

    lv_obj_t * sw = lv_event_get_target(e);
    bool is_on = lv_obj_has_state(sw, LV_STATE_CHECKED);

    /* [1] ควบคุม Hardware LED จริง */
    aic_gpio_led_set(AIC_LED_RED, is_on);

    /* [2] อัพเดท LVGL LED indicator */
    if (is_on) {
        lv_led_on(led_indicator);
    } else {
        lv_led_off(led_indicator);
    }
}
```

#### 4.2 Full Example: 3 LEDs + PWM Slider

```c
#include "aic-eec.h"

/* ===== Global Variables ===== */
static lv_obj_t * led_red_ind;
static lv_obj_t * led_green_ind;
static lv_obj_t * led_blue_ind;
static lv_obj_t * duty_label;

/* ===== Callback: Red LED Switch ===== */
static void ex6_red_cb(lv_event_t * e)
{
    if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
    lv_obj_t * sw = lv_event_get_target(e);
    bool on = lv_obj_has_state(sw, LV_STATE_CHECKED);

    aic_gpio_led_set(AIC_LED_RED, on);       /* Hardware */
    on ? lv_led_on(led_red_ind) : lv_led_off(led_red_ind);  /* UI */
}

/* ===== Callback: Green LED Switch ===== */
static void ex6_green_cb(lv_event_t * e)
{
    if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
    lv_obj_t * sw = lv_event_get_target(e);
    bool on = lv_obj_has_state(sw, LV_STATE_CHECKED);

    aic_gpio_led_set(AIC_LED_GREEN, on);     /* Hardware */
    on ? lv_led_on(led_green_ind) : lv_led_off(led_green_ind);
}

/* ===== Callback: Blue LED PWM Slider ===== */
static void ex6_slider_cb(lv_event_t * e)
{
    if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
    lv_obj_t * slider = lv_event_get_target(e);
    int duty = lv_slider_get_value(slider);

    /* [1] Hardware: PWM duty cycle */
    aic_gpio_pwm_set_duty(AIC_LED_BLUE, duty);

    /* [2] UI: LED indicator brightness (scale 0-100 -> 0-255) */
    lv_led_set_brightness(led_blue_ind, (uint8_t)(duty * 255 / 100));

    /* [3] UI: Label update */
    lv_label_set_text_fmt(duty_label, "Duty: %d%%", duty);
}

/* ===== Main Function ===== */
void part1_ex6_hw_led_control(void)
{
    /* ============================== */
    /*    HARDWARE INITIALIZATION     */
    /* ============================== */
    aic_gpio_init();                       /* [1] GPIO subsystem */
    aic_gpio_pwm_init(AIC_LED_BLUE);       /* [2] PWM for Blue LED */

    /* ============================== */
    /*         LVGL UI SETUP          */
    /* ============================== */
    lv_obj_t * scr = lv_screen_active();
    lv_obj_set_style_bg_color(scr, lv_color_hex(0x1a1a2e), 0);

    /* --- Title --- */
    lv_obj_t * title = lv_label_create(scr);
    lv_label_set_text(title, "Lab 6: HW LED Control");
    lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), 0);
    lv_obj_set_style_text_font(title, &lv_font_montserrat_18, 0);
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10);

    /* --- Container for LED controls --- */
    lv_obj_t * cont = lv_obj_create(scr);
    lv_obj_set_size(cont, 440, 200);
    lv_obj_align(cont, LV_ALIGN_CENTER, 0, 10);
    lv_obj_set_style_bg_color(cont, lv_color_hex(0x16213e), 0);
    lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_style_pad_row(cont, 10, 0);
    lv_obj_set_style_pad_all(cont, 15, 0);

    /* --- Row 1: Red LED --- */
    lv_obj_t * row1 = lv_obj_create(cont);
    lv_obj_set_size(row1, LV_PCT(100), 45);
    lv_obj_set_flex_flow(row1, LV_FLEX_FLOW_ROW);
    lv_obj_set_style_pad_all(row1, 5, 0);
    lv_obj_remove_flag(row1, LV_OBJ_FLAG_SCROLLABLE);

    led_red_ind = lv_led_create(row1);
    lv_led_set_color(led_red_ind, lv_palette_main(LV_PALETTE_RED));
    lv_obj_set_size(led_red_ind, 25, 25);
    lv_led_off(led_red_ind);

    lv_obj_t * lbl_red = lv_label_create(row1);
    lv_label_set_text(lbl_red, "Red LED");
    lv_obj_set_style_text_color(lbl_red, lv_color_hex(0xFFFFFF), 0);

    lv_obj_t * sw_red = lv_switch_create(row1);
    lv_obj_add_event_cb(sw_red, ex6_red_cb, LV_EVENT_VALUE_CHANGED, NULL);

    /* --- Row 2: Green LED --- */
    lv_obj_t * row2 = lv_obj_create(cont);
    lv_obj_set_size(row2, LV_PCT(100), 45);
    lv_obj_set_flex_flow(row2, LV_FLEX_FLOW_ROW);
    lv_obj_set_style_pad_all(row2, 5, 0);
    lv_obj_remove_flag(row2, LV_OBJ_FLAG_SCROLLABLE);

    led_green_ind = lv_led_create(row2);
    lv_led_set_color(led_green_ind, lv_palette_main(LV_PALETTE_GREEN));
    lv_obj_set_size(led_green_ind, 25, 25);
    lv_led_off(led_green_ind);

    lv_obj_t * lbl_green = lv_label_create(row2);
    lv_label_set_text(lbl_green, "Green LED");
    lv_obj_set_style_text_color(lbl_green, lv_color_hex(0xFFFFFF), 0);

    lv_obj_t * sw_green = lv_switch_create(row2);
    lv_obj_add_event_cb(sw_green, ex6_green_cb, LV_EVENT_VALUE_CHANGED, NULL);

    /* --- Row 3: Blue LED + PWM Slider --- */
    lv_obj_t * row3 = lv_obj_create(cont);
    lv_obj_set_size(row3, LV_PCT(100), 50);
    lv_obj_set_flex_flow(row3, LV_FLEX_FLOW_ROW);
    lv_obj_set_style_pad_all(row3, 5, 0);
    lv_obj_remove_flag(row3, LV_OBJ_FLAG_SCROLLABLE);

    led_blue_ind = lv_led_create(row3);
    lv_led_set_color(led_blue_ind, lv_palette_main(LV_PALETTE_BLUE));
    lv_obj_set_size(led_blue_ind, 25, 25);
    lv_led_off(led_blue_ind);

    lv_obj_t * lbl_blue = lv_label_create(row3);
    lv_label_set_text(lbl_blue, "Blue PWM");
    lv_obj_set_style_text_color(lbl_blue, lv_color_hex(0xFFFFFF), 0);

    lv_obj_t * slider = lv_slider_create(row3);
    lv_obj_set_width(slider, 180);
    lv_slider_set_range(slider, 0, 100);
    lv_slider_set_value(slider, 0, LV_ANIM_OFF);
    lv_obj_add_event_cb(slider, ex6_slider_cb, LV_EVENT_VALUE_CHANGED, NULL);

    duty_label = lv_label_create(row3);
    lv_label_set_text(duty_label, "Duty: 0%");
    lv_obj_set_style_text_color(duty_label, lv_color_hex(0x00BFFF), 0);
}
```

#### 4.3 อธิบายโค้ดทีละขั้นตอน

<table><thead><tr><th width="91.04547119140625">ขั้นตอน</th><th width="366.41619873046875">โค้ด</th><th>คำอธิบาย</th></tr></thead><tbody><tr><td>1</td><td><code>aic_gpio_init()</code></td><td>เริ่มต้น GPIO subsystem (<strong>ต้องเรียกก่อน</strong>)</td></tr><tr><td>2</td><td><code>aic_gpio_pwm_init(AIC_LED_BLUE)</code></td><td>เปิด PWM สำหรับ Blue LED</td></tr><tr><td>3</td><td><code>lv_switch_create()</code></td><td>สร้าง Switch widget สำหรับ Red/Green</td></tr><tr><td>4</td><td><code>lv_slider_create()</code></td><td>สร้าง Slider สำหรับ Blue PWM</td></tr><tr><td>5</td><td><code>lv_obj_add_event_cb(sw, cb, LV_EVENT_VALUE_CHANGED, ...)</code></td><td>ผูก callback</td></tr><tr><td>6</td><td><code>aic_gpio_led_set(AIC_LED_RED, on)</code></td><td>ใน callback: ควบคุม LED จริง</td></tr><tr><td>7</td><td><code>aic_gpio_pwm_set_duty(AIC_LED_BLUE, duty)</code></td><td>ใน callback: ควบคุม PWM</td></tr></tbody></table>

***

### 5. องค์ความรู้และเทคนิค

#### 5.1 Pattern: Event Callback -> Hardware Action

ทุกครั้งที่ต้องการควบคุม Hardware จาก UI ให้ใช้ pattern นี้:

```c
static void my_switch_cb(lv_event_t * e)
{
    /* [1] Filter event type */
    if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;

    /* [2] Read UI state */
    lv_obj_t * sw = lv_event_get_target(e);
    bool is_on = lv_obj_has_state(sw, LV_STATE_CHECKED);

    /* [3] Apply to Hardware */
    aic_gpio_led_set(AIC_LED_RED, is_on);

    /* [4] Update UI feedback */
    is_on ? lv_led_on(indicator) : lv_led_off(indicator);
}
```

#### 5.2 Pattern: PWM Duty Mapping

```c
/* LVGL Slider: 0-100 -> PWM duty: 0-100 (same range) */
int duty = lv_slider_get_value(slider);
aic_gpio_pwm_set_duty(AIC_LED_BLUE, duty);

/* LVGL LED indicator brightness: 0-255 */
lv_led_set_brightness(led_ind, (uint8_t)(duty * 255 / 100));
```

#### 5.3 สิ่งที่ต้องระวัง

| หัวข้อ                 | รายละเอียด                                                          |
| ---------------------- | ------------------------------------------------------------------- |
| **GPIO Init First**    | ต้องเรียก `aic_gpio_init()` ก่อนเสมอ ไม่งั้น LED ไม่ทำงาน           |
| **PWM Init**           | `aic_gpio_pwm_init()` รองรับ Blue LED เท่านั้น                      |
| **Event Filter**       | ตรวจสอบ `lv_event_get_code()` ทุกครั้ง ป้องกัน callback ถูกเรียกซ้ำ |
| **LVGL Thread Safety** | เรียก LVGL functions ได้เฉพาะใน LVGL context (callback, timer)      |
| **PWM Duty Range**     | 0 = ดับ, 100 = สว่างเต็ม, ค่านอกช่วงจะถูก clamp                     |

#### 5.4 Application ในอุตสาหกรรม

* **Factory HMI**: ควบคุม Status Indicator LED จากหน้าจอสัมผัส
* **Building Automation**: ควบคุมไฟ (ON/OFF + Dimming) ผ่าน Touch Panel
* **Medical Equipment**: LED Alert system ที่ผู้ใช้ควบคุมได้

***

### 6. แบบฝึกหัด (Exercises)

#### แบบฝึกหัดที่ 1: LED Pattern Sequence

**โจทย์**: สร้างปุ่ม "Start Pattern" ที่เมื่อกดแล้ว LED จะ toggle สลับกันเป็นลำดับ: Red -> Green -> Blue -> Red -> Green -> Blue (วนซ้ำ)

**ข้อกำหนด**:

* ใช้ `lv_timer_create()` สร้าง timer ที่ทำงานทุก 500ms
* แต่ละครั้ง timer callback ให้เปิด LED ตัวถัดไป และปิดตัวก่อนหน้า
* มีปุ่ม "Stop" เพื่อหยุด pattern และปิด LED ทั้งหมด
* แสดง Label บอกสถานะ: "Running: RED" / "Stopped"

**Hints**:

* ใช้ตัวแปร `static int current_led = 0;` เก็บ index LED ปัจจุบัน
* `lv_timer_create(cb, 500, NULL)` สร้าง timer
* `lv_timer_delete(timer)` หยุด timer

#### แบบฝึกหัดที่ 2: RGB Brightness Control Panel

**โจทย์**: สร้างหน้า Control Panel ที่มี Slider 3 ตัว สำหรับ Red, Green, Blue

**ข้อกำหนด**:

* Red Slider (0-1): 0 = OFF, 1 = ON (เพราะ Red ไม่มี PWM)
* Green Slider (0-1): 0 = OFF, 1 = ON (เพราะ Green ไม่มี PWM)
* Blue Slider (0-100): ควบคุม PWM duty cycle
* แสดง Preview Box ที่เปลี่ยนสีตาม RGB combination
* แสดงค่า R, G, B เป็นตัวเลข

**Hints**:

* ใช้ `lv_obj_set_style_bg_color()` เปลี่ยนสี Preview Box
* `lv_color_make(r, g, b)` สร้างสี โดย r, g, b เป็น 0-255

***
