# GPIO Integration

## Lab 4: รวมทุกอย่าง — POT ควบคุม LED Blink Rate

#### วัตถุประสงค์

* **Integration**: รวมความรู้จาก Lab 1-3 (LED, Button, ADC)
* **Real Application**: สร้าง Interactive LED Controller
* **State Machine**: จัดการหลาย input/output พร้อมกัน

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

* **Multiple Inputs:** จัดการ POT + Button พร้อมกัน
* **Value Mapping:** แปลงค่า POT เป็น delay time
* **Mode Switching:** สลับโหมดด้วย button
* **Non-Blocking Design:** ทำหลายอย่างพร้อมกัน

***

### Application Design

```bash
┌─────────────────────────────────────────────────────────────────┐
│                  Interactive LED Controller                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   INPUTS:                                                       │
│   ════════                                                      │
│   POT (P15_1)     ────►  LED Blink Rate                         │
│   └─ 0%   = 1000ms (ช้าสุด)                                       │
│   └─ 50%  = 525ms                                               │
│   └─ 100% = 50ms  (เร็วสุด)                                       │
│                                                                 │
│   Button (USER_BTN1) ────►  Toggle Mode                         │
│   └─ Active LOW (กด = 0)                                        │
│   └─ Debounce 50ms                                              │
│                                                                 │
│   MODES:                                                        │
│   ═══════                                                       │
│   MODE_NORMAL:  LED blinks at POT-controlled speed              │
│   MODE_FAST:    LED blinks at 2x speed (delay / 2)              │
│                                                                 │
│   OUTPUT:                                                       │
│   ═══════                                                       │
│   LED (USER_LED1) ────►  Blinks based on calculated delay       │
│   Serial Terminal ────►  Real-time ASCII status bar             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

***

### Lab 4.1 : Code Implementation

#### Step 1: Macros Configuration

```c
#include "cybsp.h"
#include "retarget_io_init.h"
#include <stdbool.h>

/*******************************************************************************
 * Macros
 ******************************************************************************/
/* System Configuration */
#define CM55_BOOT_WAIT_TIME_USEC    (10U)

/* ADC Configuration */
#define SAR_ADC_INDEX               (0U)
#define SAR_ADC_SEQUENCER           (0U)
#define SAR_ADC_CHANNEL             (0U)
#define SAR_ADC_VREF_MV             (1800U)
#define ADC_READ_INTERVAL_MS        (100U)

/* Button Configuration */
#define USER_BTN_PORT               CYBSP_USER_BTN1_PORT
#define USER_BTN_PIN                CYBSP_USER_BTN1_PIN
#define DEBOUNCE_DELAY_MS           (50U)

/* Button is Active LOW: pressed = 0 */
#define IS_BUTTON_PRESSED()         (Cy_GPIO_Read(USER_BTN_PORT, USER_BTN_PIN) == 0)

/* LED Control Macros (Active LOW on PSoC Edge E84) */
#define LED_ON()                    Cy_GPIO_Clr(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)
#define LED_OFF()                   Cy_GPIO_Set(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)
#define LED_TOGGLE()                Cy_GPIO_Inv(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)

/* LED Blink Speed Limits */
#define BLINK_DELAY_MIN_MS          (50U)
#define BLINK_DELAY_MAX_MS          (1000U)
```

#### Step 2: Mode Definition

```c
/* Mode Definitions */
typedef enum {
    MODE_NORMAL = 0,    // LED blinks at POT-controlled speed
    MODE_FAST   = 1     // LED blinks at 2x speed
} led_mode_t;

/* Global Variables */
static bool adc_initialized = false;
static led_mode_t current_mode = MODE_NORMAL;
static uint32_t mode_change_count = 0;
```

#### Step 3: Helper Functions

**read\_button\_with\_debounce() - Delay-Based Debounce**

> **หมายเหตุ:** PSoC Edge ไม่มี `Cy_SysLib_GetTimerTick()` จึงใช้ Delay-Based Debounce แทน

```c
/*******************************************************************************
* Function Name: read_button_with_debounce
********************************************************************************
* Summary:
*   Reads the user button with software debouncing.
*   Uses delay-based debounce suitable for PSoC Edge.
*
* Return:
*   bool - true if a valid button press was detected
*******************************************************************************/
static bool read_button_with_debounce(void)
{
    static bool last_state = false;

    bool current_state = IS_BUTTON_PRESSED();

    /* Detect rising edge (button just pressed) */
    if (current_state && !last_state)
    {
        /* Wait for debounce period */
        Cy_SysLib_Delay(DEBOUNCE_DELAY_MS);

        /* Re-read to confirm button is still pressed */
        if (IS_BUTTON_PRESSED())
        {
            last_state = true;
            return true;
        }
    }

    /* Update state when button is released */
    if (!current_state)
    {
        last_state = false;
    }

    return false;
}
```

**map\_pot\_to\_delay() - แปลงค่า POT เป็น Delay**

```c
/*******************************************************************************
* Function Name: map_pot_to_delay
********************************************************************************
* Summary:
*   Maps potentiometer percentage (0-100%) to LED blink delay.
*   Inverted mapping: higher pot value = faster blink
*
*   Formula: delay = MAX - (percentage * (MAX - MIN) / 100)
*
*   Examples:
*     0%   → 1000ms (slowest)
*     50%  → 525ms
*     100% → 50ms   (fastest)
*
* Parameters:
*   pot_percentage - Potentiometer reading as percentage (0-100)
*
* Return:
*   uint32_t - Delay in milliseconds (50-1000)
*******************************************************************************/
static uint32_t map_pot_to_delay(uint8_t pot_percentage)
{
    uint32_t delay;

    /* Map 0-100% to 1000-50ms (inverted) */
    delay = BLINK_DELAY_MAX_MS - ((uint32_t)pot_percentage *
            (BLINK_DELAY_MAX_MS - BLINK_DELAY_MIN_MS) / 100);

    /* Ensure minimum delay */
    if (delay < BLINK_DELAY_MIN_MS)
    {
        delay = BLINK_DELAY_MIN_MS;
    }

    return delay;
}
```

**print\_status\_bar() - ASCII Status Bar**

```c
/*******************************************************************************
* Function Name: print_status_bar
********************************************************************************
* Summary:
*   Prints an ASCII status bar showing potentiometer percentage,
*   current delay, and operating mode.
*******************************************************************************/
static void print_status_bar(uint8_t percentage, uint32_t delay_ms, led_mode_t mode)
{
    int i;
    int bar_length = percentage / 5;  /* 0-20 characters */

    printf("\r[");

    for (i = 0; i < 20; i++)
    {
        if (i < bar_length)
        {
            printf("#");
        }
        else
        {
            printf("-");
        }
    }

    printf("] %3d%% | %4lums | %s     ",
           percentage,
           (unsigned long)delay_ms,
           (mode == MODE_FAST) ? "FAST" : "NORMAL");

    fflush(stdout);
}
```

#### Step 4: Main Function (Non-Blocking Design)

```c
/*******************************************************************************
* Main Function
*******************************************************************************/
int main(void)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;
    int16_t voltage_mv;
    uint8_t percentage;
    uint32_t base_delay;
    uint32_t actual_delay;
    uint32_t elapsed_time = 0;
    uint32_t last_toggle_time = 0;
    uint32_t last_adc_time = 0;

    /* Initialize the device and board peripherals */
    result = cybsp_init();
    if (CY_RSLT_SUCCESS != result) handle_app_error();

    __enable_irq();
    init_retarget_io();

    /* Clear screen */
    printf("\x1b[2J\x1b[;H");
    printf("***********************************************************\r\n");
    printf("        PSOC Edge MCU: Interactive LED Controller          \r\n");
    printf("***********************************************************\r\n\n");

    /* Initialize SAR ADC */
    result = init_adc();
    if (CY_RSLT_SUCCESS != result)
    {
        printf("ADC initialization failed!\r\n");
        handle_app_error();
    }

    /* Print instructions */
    printf("Controls:\r\n");
    printf("  - Potentiometer (P15_1): Adjust LED blink speed\r\n");
    printf("  - Button (USER_BTN1):    Toggle Normal/Fast mode\r\n\n");
    printf("Speed Range: 50ms (fast) to 1000ms (slow)\r\n");
    printf("Fast Mode:   2x speed (half delay)\r\n\n");

    /* Enable CM55 */
    Cy_SysEnableCM55(MXCM55, CY_CM55_APP_BOOT_ADDR, CM55_BOOT_WAIT_TIME_USEC);

    /* Initial ADC read */
    voltage_mv = read_potentiometer_mv();
    percentage = get_pot_percentage(voltage_mv);
    base_delay = map_pot_to_delay(percentage);
    actual_delay = base_delay;

    printf("Starting LED Controller...\r\n\n");

    for(;;)
    {
        /* 1. Check button for mode toggle */
        if (read_button_with_debounce())
        {
            /* Toggle mode */
            current_mode = (current_mode == MODE_NORMAL) ? MODE_FAST : MODE_NORMAL;
            mode_change_count++;

            printf("\n>>> Mode changed to: %s (count: %lu)\r\n\n",
                   (current_mode == MODE_FAST) ? "FAST" : "NORMAL",
                   (unsigned long)mode_change_count);
        }

        /* 2. Read ADC periodically (every 100ms) */
        if ((elapsed_time - last_adc_time) >= ADC_READ_INTERVAL_MS)
        {
            voltage_mv = read_potentiometer_mv();
            percentage = get_pot_percentage(voltage_mv);
            base_delay = map_pot_to_delay(percentage);

            /* 3. Apply mode multiplier */
            if (current_mode == MODE_FAST)
            {
                actual_delay = base_delay / 2;
                if (actual_delay < BLINK_DELAY_MIN_MS / 2)
                {
                    actual_delay = BLINK_DELAY_MIN_MS / 2;
                }
            }
            else
            {
                actual_delay = base_delay;
            }

            /* Print status bar */
            print_status_bar(percentage, actual_delay, current_mode);

            last_adc_time = elapsed_time;
        }

        /* 4. Toggle LED based on calculated delay */
        if ((elapsed_time - last_toggle_time) >= actual_delay)
        {
            LED_TOGGLE();
            last_toggle_time = elapsed_time;
        }

        /* 5. Small delay for loop timing */
        Cy_SysLib_Delay(10);
        elapsed_time += 10;
    }
}
```

***

### 4. Flowchart

```bash
┌─────────────────────────────────────────────────────────────────┐
│              Interactive LED Controller Flowchart               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌──────────────────┐                                          │
│   │      START       │                                          │
│   └────────┬─────────┘                                          │
│            │                                                    │
│            ▼                                                    │
│   ┌──────────────────┐                                          │
│   │  cybsp_init()    │                                          │
│   │  init_adc()      │                                          │
│   │  Enable CM55     │                                          │
│   └────────┬─────────┘                                          │
│            │                                                    │
│            ▼                                                    │
│   ╔══════════════════════════════════════════════════════╗      │
│   ║                    MAIN LOOP                         ║      │
│   ╠══════════════════════════════════════════════════════╣      │
│   ║                                                      ║      │
│   ║  ┌─────────────────────────────────────────────┐     ║      │
│   ║  │  1. Check Button (with debounce)            │     ║      │
│   ║  │     If pressed: Toggle MODE                 │     ║      │
│   ║  │     MODE_NORMAL ←→ MODE_FAST                │     ║      │
│   ║  └─────────────────────────────────────────────┘     ║      │
│   ║                        │                             ║      │
│   ║                        ▼                             ║      │
│   ║  ┌─────────────────────────────────────────────┐     ║      │
│   ║  │  2. Read ADC (every 100ms)                  │     ║      │
│   ║  │     percentage = get_pot_percentage()       │     ║      │
│   ║  │     base_delay = map_pot_to_delay()         │     ║      │
│   ║  └─────────────────────────────────────────────┘     ║      │
│   ║                        │                             ║      │
│   ║                        ▼                             ║      │
│   ║  ┌─────────────────────────────────────────────┐     ║      │
│   ║  │  3. Apply Mode Multiplier                   │     ║      │
│   ║  │     NORMAL: actual_delay = base_delay       │     ║      │
│   ║  │     FAST:   actual_delay = base_delay / 2   │     ║      │
│   ║  └─────────────────────────────────────────────┘     ║      │
│   ║                        │                             ║      │
│   ║                        ▼                             ║      │
│   ║  ┌─────────────────────────────────────────────┐     ║      │
│   ║  │  4. Toggle LED (if delay elapsed)           │     ║      │
│   ║  │     LED_TOGGLE()                            │     ║      │
│   ║  └─────────────────────────────────────────────┘     ║      │
│   ║                        │                             ║      │
│   ║                        ▼                             ║      │
│   ║  ┌─────────────────────────────────────────────┐     ║      │
│   ║  │  5. Print Status Bar                        │     ║      │
│   ║  │     [####----] 50% | 525ms | NORMAL         │     ║      │
│   ║  └─────────────────────────────────────────────┘     ║      │
│   ║                        │                             ║      │
│   ║                        ▼                             ║      │
│   ║  ┌─────────────────────────────────────────────┐     ║      │
│   ║  │  6. Delay 10ms + elapsed_time += 10         │     ║      │
│   ║  └────────────────────┬────────────────────────┘     ║      │
│   ║                       │                              ║      │
│   ╚═══════════════════════╪══════════════════════════════╝      │
│                           │                                     │
│                           └──────────► (repeat)                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

***

### 5. State Diagram

```bash
┌─────────────────────────────────────────────────────────────────┐
│                     Mode State Machine                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌──────────────────┐       Button Press      ┌──────────────┐ │
│   │                  │ ◄─────────────────────► │              │ │
│   │   MODE_NORMAL    │                         │  MODE_FAST   │ │
│   │    (1x speed)    │                         │  (2x speed)  │ │
│   │                  │                         │              │ │
│   └──────────────────┘                         └──────────────┘ │
│          │                                            │         │
│          │                                            │         │
│          ▼                                            ▼         │
│   LED Delay = POT delay                 LED Delay = POT delay/2 │
│   (50ms - 1000ms)                       (25ms - 500ms)          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

***

### 6. ตัวอย่าง Output

```bash
***********************************************************
        PSOC Edge MCU: Interactive LED Controller
***********************************************************

Controls:
  - Potentiometer (P15_1): Adjust LED blink speed
  - Button (USER_BTN1):    Toggle Normal/Fast mode

Speed Range: 50ms (fast) to 1000ms (slow)
Fast Mode:   2x speed (half delay)

Starting LED Controller...

[--------------------]   0% | 1000ms | NORMAL
[#####---------------]  25% |  762ms | NORMAL
[##########----------]  50% |  525ms | NORMAL

>>> Mode changed to: FAST (count: 1)

[##########----------]  50% |  262ms | FAST
[###############-----]  75% |  143ms | FAST
[####################] 100% |   25ms | FAST

>>> Mode changed to: NORMAL (count: 2)

[####################] 100% |   50ms | NORMAL
```

***

### <mark style="color:blue;">Program Code ทั้งหมด</mark>

```c
/*******************************************************************************
* File Name        : main.c
*
* Description      : GPIO Integration - Interactive LED Controller
*                    Combines Button + LED + ADC (Potentiometer)
*
* Features:
*   - Potentiometer controls LED blink speed (50ms - 1000ms)
*   - Button toggles between Normal and Fast mode (2x speed)
*   - Non-blocking design pattern
*   - Real-time ASCII status bar display
*
*******************************************************************************/

/*******************************************************************************
* Header Files
*******************************************************************************/
#include "cybsp.h"
#include "retarget_io_init.h"
#include <stdbool.h>

/*******************************************************************************
 * Macros
 ******************************************************************************/
/* System Configuration */
#define CM55_BOOT_WAIT_TIME_USEC    (10U)

/* ADC Configuration */
#define SAR_ADC_INDEX               (0U)
#define SAR_ADC_SEQUENCER           (0U)
#define SAR_ADC_CHANNEL             (0U)
#define SAR_ADC_VREF_MV             (1800U)
#define ADC_READ_INTERVAL_MS        (100U)

/* Button Configuration */
#define USER_BTN_PORT               CYBSP_USER_BTN1_PORT
#define USER_BTN_PIN                CYBSP_USER_BTN1_PIN
#define DEBOUNCE_DELAY_MS           (50U)

/* Button is Active LOW: pressed = 0 */
#define IS_BUTTON_PRESSED()         (Cy_GPIO_Read(USER_BTN_PORT, USER_BTN_PIN) == 0)

/* LED Control Macros */
#define LED_ON()                    Cy_GPIO_Clr(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)
#define LED_OFF()                   Cy_GPIO_Set(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)
#define LED_TOGGLE()                Cy_GPIO_Inv(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)

/* LED Blink Speed Limits */
#define BLINK_DELAY_MIN_MS          (50U)
#define BLINK_DELAY_MAX_MS          (1000U)

/* Mode Definitions */
typedef enum {
    MODE_NORMAL = 0,
    MODE_FAST   = 1
} led_mode_t;

/*******************************************************************************
* Global Variables
*******************************************************************************/
static bool adc_initialized = false;
static led_mode_t current_mode = MODE_NORMAL;
static uint32_t mode_change_count = 0;

/*******************************************************************************
* Function Prototypes
*******************************************************************************/
static cy_rslt_t init_adc(void);
static int16_t read_potentiometer_mv(void);
static uint8_t get_pot_percentage(int16_t voltage_mv);
static bool read_button_with_debounce(void);
static uint32_t map_pot_to_delay(uint8_t pot_percentage);
static void print_status_bar(uint8_t percentage, uint32_t delay_ms, led_mode_t mode);

/*******************************************************************************
* Function Name: init_adc
********************************************************************************
* Summary:
*   Initializes the SAR ADC using autonomous analog control.
*
* Return:
*   cy_rslt_t - CY_RSLT_SUCCESS if initialization successful
*******************************************************************************/
static cy_rslt_t init_adc(void)
{
    cy_rslt_t result;

    result = Cy_AutAnalog_Init(&autonomous_analog_init);

    if (CY_AUTANALOG_SUCCESS != result)
    {
        return result;
    }

    Cy_AutAnalog_SetInterruptMask(CY_AUTANALOG_INT_SAR0_RESULT);
    Cy_AutAnalog_StartAutonomousControl();

    adc_initialized = true;
    return CY_RSLT_SUCCESS;
}

/*******************************************************************************
* Function Name: read_potentiometer_mv
********************************************************************************
* Summary:
*   Reads the potentiometer value from ADC and converts to millivolts.
*
* Return:
*   int16_t - Voltage in millivolts (0-1800 mV)
*******************************************************************************/
static int16_t read_potentiometer_mv(void)
{
    int32_t adc_count;
    int16_t voltage_mv;

    adc_count = Cy_AutAnalog_SAR_ReadResult(SAR_ADC_INDEX,
                                            CY_AUTANALOG_SAR_INPUT_GPIO,
                                            SAR_ADC_CHANNEL);

    voltage_mv = Cy_AutAnalog_SAR_CountsTo_mVolts(SAR_ADC_INDEX,
                                                   false,
                                                   SAR_ADC_SEQUENCER,
                                                   CY_AUTANALOG_SAR_INPUT_GPIO,
                                                   SAR_ADC_CHANNEL,
                                                   SAR_ADC_VREF_MV,
                                                   adc_count);

    return voltage_mv;
}

/*******************************************************************************
* Function Name: get_pot_percentage
********************************************************************************
* Summary:
*   Converts potentiometer voltage to percentage (0-100%).
*
* Parameters:
*   voltage_mv - Input voltage in millivolts
*
* Return:
*   uint8_t - Percentage value (0-100)
*******************************************************************************/
static uint8_t get_pot_percentage(int16_t voltage_mv)
{
    int32_t percentage;

    if (voltage_mv < 0)
    {
        voltage_mv = 0;
    }
    else if (voltage_mv > SAR_ADC_VREF_MV)
    {
        voltage_mv = SAR_ADC_VREF_MV;
    }

    percentage = ((int32_t)voltage_mv * 100) / SAR_ADC_VREF_MV;

    return (uint8_t)percentage;
}

/*******************************************************************************
* Function Name: read_button_with_debounce
********************************************************************************
* Summary:
*   Reads the user button with software debouncing.
*   Uses delay-based debounce suitable for PSoC Edge.
*
* Return:
*   bool - true if a valid button press was detected
*******************************************************************************/
static bool read_button_with_debounce(void)
{
    static bool last_state = false;

    bool current_state = IS_BUTTON_PRESSED();

    /* Detect rising edge (button just pressed) */
    if (current_state && !last_state)
    {
        /* Wait for debounce period */
        Cy_SysLib_Delay(DEBOUNCE_DELAY_MS);

        /* Re-read to confirm button is still pressed */
        if (IS_BUTTON_PRESSED())
        {
            last_state = true;
            return true;
        }
    }

    /* Update state when button is released */
    if (!current_state)
    {
        last_state = false;
    }

    return false;
}

/*******************************************************************************
* Function Name: map_pot_to_delay
********************************************************************************
* Summary:
*   Maps potentiometer percentage (0-100%) to LED blink delay.
*   0% = slowest (1000ms), 100% = fastest (50ms)
*   Inverted mapping: higher pot value = faster blink
*
* Parameters:
*   pot_percentage - Potentiometer reading as percentage (0-100)
*
* Return:
*   uint32_t - Delay in milliseconds (50-1000)
*******************************************************************************/
static uint32_t map_pot_to_delay(uint8_t pot_percentage)
{
    uint32_t delay;

    /* Map 0-100% to 1000-50ms (inverted) */
    /* delay = MAX - (percentage * (MAX - MIN) / 100) */
    delay = BLINK_DELAY_MAX_MS - ((uint32_t)pot_percentage *
            (BLINK_DELAY_MAX_MS - BLINK_DELAY_MIN_MS) / 100);

    /* Ensure minimum delay */
    if (delay < BLINK_DELAY_MIN_MS)
    {
        delay = BLINK_DELAY_MIN_MS;
    }

    return delay;
}

/*******************************************************************************
* Function Name: print_status_bar
********************************************************************************
* Summary:
*   Prints an ASCII status bar showing potentiometer percentage,
*   current delay, and operating mode.
*
* Parameters:
*   percentage - Current pot percentage
*   delay_ms   - Current blink delay in ms
*   mode       - Current operating mode
*******************************************************************************/
static void print_status_bar(uint8_t percentage, uint32_t delay_ms, led_mode_t mode)
{
    int i;
    int bar_length = percentage / 5;  /* 0-20 characters */

    printf("\r[");

    for (i = 0; i < 20; i++)
    {
        if (i < bar_length)
        {
            printf("#");
        }
        else
        {
            printf("-");
        }
    }

    printf("] %3d%% | %4lums | %s     ",
           percentage,
           (unsigned long)delay_ms,
           (mode == MODE_FAST) ? "FAST" : "NORMAL");

    fflush(stdout);
}

/*******************************************************************************
* Function Name: main
********************************************************************************
* Summary:
*   Main function - GPIO Integration Demo
*
*   Features:
*   - Potentiometer controls LED blink speed (50-1000ms)
*   - Button toggles between Normal and Fast mode
*   - Fast mode doubles the blink speed (halves the delay)
*   - Real-time ASCII status bar display
*
* Return:
*   int
*******************************************************************************/
int main(void)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;
    int16_t voltage_mv;
    uint8_t percentage;
    uint32_t base_delay;
    uint32_t actual_delay;
    uint32_t elapsed_time = 0;
    uint32_t last_toggle_time = 0;
    uint32_t last_adc_time = 0;

    /* Initialize the device and board peripherals */
    result = cybsp_init();

    if (CY_RSLT_SUCCESS != result)
    {
        handle_app_error();
    }

    /* Enable global interrupts */
    __enable_irq();

    /* Initialize retarget-io middleware */
    init_retarget_io();

    /* Clear screen */
    printf("\x1b[2J\x1b[;H");
    printf("***********************************************************\r\n");
    printf("        PSOC Edge MCU: Interactive LED Controller          \r\n");
    printf("***********************************************************\r\n\n");

    /* Initialize SAR ADC */
    result = init_adc();

    if (CY_RSLT_SUCCESS != result)
    {
        printf("ADC initialization failed!\r\n");
        handle_app_error();
    }

    /* Print instructions */
    printf("Controls:\r\n");
    printf("  - Potentiometer (P15_1): Adjust LED blink speed\r\n");
    printf("  - Button (USER_BTN1):    Toggle Normal/Fast mode\r\n\n");
    printf("Speed Range: 50ms (fast) to 1000ms (slow)\r\n");
    printf("Fast Mode:   2x speed (half delay)\r\n\n");

    /* Enable CM55 */
    Cy_SysEnableCM55(MXCM55, CY_CM55_APP_BOOT_ADDR, CM55_BOOT_WAIT_TIME_USEC);

    /* Initial ADC read */
    voltage_mv = read_potentiometer_mv();
    percentage = get_pot_percentage(voltage_mv);
    base_delay = map_pot_to_delay(percentage);
    actual_delay = base_delay;

    printf("Starting LED Controller...\r\n\n");

    for(;;)
    {
        /* Check button for mode toggle */
        if (read_button_with_debounce())
        {
            /* Toggle mode */
            if (current_mode == MODE_NORMAL)
            {
                current_mode = MODE_FAST;
            }
            else
            {
                current_mode = MODE_NORMAL;
            }

            mode_change_count++;

            printf("\n>>> Mode changed to: %s (count: %lu)\r\n\n",
                   (current_mode == MODE_FAST) ? "FAST" : "NORMAL",
                   (unsigned long)mode_change_count);
        }

        /* Read ADC periodically */
        if ((elapsed_time - last_adc_time) >= ADC_READ_INTERVAL_MS)
        {
            voltage_mv = read_potentiometer_mv();
            percentage = get_pot_percentage(voltage_mv);
            base_delay = map_pot_to_delay(percentage);

            /* Apply mode multiplier */
            if (current_mode == MODE_FAST)
            {
                actual_delay = base_delay / 2;
                if (actual_delay < BLINK_DELAY_MIN_MS / 2)
                {
                    actual_delay = BLINK_DELAY_MIN_MS / 2;
                }
            }
            else
            {
                actual_delay = base_delay;
            }

            /* Print status bar */
            print_status_bar(percentage, actual_delay, current_mode);

            last_adc_time = elapsed_time;
        }

        /* Toggle LED based on calculated delay */
        if ((elapsed_time - last_toggle_time) >= actual_delay)
        {
            LED_TOGGLE();
            last_toggle_time = elapsed_time;
        }

        /* Small delay for loop timing */
        Cy_SysLib_Delay(10);
        elapsed_time += 10;
    }
}
/* [] END OF FILE */
```

***

### 7. แบบฝึกหัด

#### Exercise 1: Three Modes (Triple Speed)

{% hint style="info" %}
**Hint**

```c
/* Mode Definitions */
typedef enum {
    MODE_NORMAL = 0,
    MODE_FAST   = 1,
    MODE_ULTRA  = 2
} led_mode_t;

/* In button handler */
if (read_button_with_debounce())
{
    current_mode = (current_mode + 1) % 3;  /* Cycle: 0→1→2→0 */

    const char* mode_names[] = {"NORMAL", "FAST (2x)", "ULTRA (4x)"};
    printf("\n>>> Mode: %s\r\n", mode_names[current_mode]);
}

/* Apply mode multiplier */
uint32_t divider[] = {1, 2, 4};
actual_delay = base_delay / divider[current_mode];
if (actual_delay < 25) {
   actual_delay = 25;
}
```

{% endhint %}

#### Exercise 2: LED Brightness Pattern

{% hint style="info" %}
**Hint**

สร้าง pattern เช่น heartbeat (สั้น-สั้น-ยาว)

```c
/* Heartbeat pattern: short-short-long pause */
static uint8_t beat_phase = 0;
static uint32_t beat_delays[] = {100, 100, 100, 100, 500};  /* 5 phases */

if ((elapsed_time - last_toggle_time) >= beat_delays[beat_phase])
{
    LED_TOGGLE();
    last_toggle_time = elapsed_time;
    beat_phase = (beat_phase + 1) % 5;
}
```

{% endhint %}

***

***


---

# 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/basic-mcu-interfacing/workshops/gpio-integration.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.
