# 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="/files/dyMUWXyq8KSIBFZbZBp6" 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

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aic-eec.com/interfacing-with-infineon-psoc-tm-edge/hmi-development/gpio-to-hmi-display/hardware-interfacing-workshops/led-control.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
