# Potentiometer (ADC)

## Lab 3: Potentiometer (ADC) — อ่านค่า Analog

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

* **Analog Input**: อ่านค่าแบบ Analog (ไม่ใช่แค่ 0/1)
* **ADC**: เข้าใจหลักการแปลง Analog → Digital
* **Scaling**: แปลงค่า ADC เป็นหน่วยที่เข้าใจได้

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

* **ADC Concept**: 12-bit resolution (0-4095)
* **Unit Conversion**: ADC counts → millivolts → percentage
* **Periodic Reading**: อ่านค่าเป็นช่วงเวลา

***

### หลักการ ADC

```
   Analog Input        ┌─────────┐        Digital Output         
   (0 - 1.8V)    ────► │   ADC   │ ────►  (0 - 4095)             
                       └─────────┘        12-bit      

Analog Input (0V - 1.8V)     ADC     Digital Output (0 - 4095)
         │                    │              │
    1.8V ├────────────────────┼─────────────→ 4095
    0.9V ├────────────────────┼─────────────→ 2048
    0.0V ├────────────────────┼─────────────→ 0
```

**Resolution 12-bit:** 2^12 = 4096 ระดับ

สูตรแปลงเป็น mV:

$$
mV = \frac{ADC\_count \times VREF\_mV}{4096}
$$

#### Hardware Info

| Component           | Pin      | หมายเหตุ       |
| ------------------- | -------- | -------------- |
| Potentiometer (POT) | P15\_1   | 0-1800mV range |
| ADC Reference       | Internal | 1.8V           |

***

### Lab 3.1 : แก้ไข Macros เดิมจาก

```c
/*******************************************************************************
 * Macros
 ******************************************************************************/
#define CM55_BOOT_WAIT_TIME_USEC    (10U) 
#define ADC_SCAN_DELAY_MSEC         (500U) <-- เดิม
#define SAR_ADC_INDEX               (0U)
#define SAR_ADC_SEQENCER            (0U)  <-- เดิม
#define SAR_ADC_CHANNEL             (0U)
#define SAR_ADC_VREF_MV             (1800U)
```

#### เป็น Macros ใหม่ , เพิ่ม Variables  และ ชื่อฟังก์ชันเพิ่มเติม ดังนี้

```c
/*******************************************************************************
 * Macros
 ******************************************************************************/
#define CM55_BOOT_WAIT_TIME_USEC    (10U)
#define ADC_READ_INTERVAL_MS        (100U)
#define SAR_ADC_INDEX               (0U)
#define SAR_ADC_SEQUENCER           (0U)
#define SAR_ADC_CHANNEL             (0U)
#define SAR_ADC_VREF_MV             (1800U)

/*******************************************************************************
* Global Variables
*******************************************************************************/
static bool adc_initialized = false;

/*******************************************************************************
* 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);
```

#### สร้างฟังก์ชัน init\_adc()

```c
/*******************************************************************************
* Function Name: init_adc
********************************************************************************
* Summary:
*   Initializes the SAR ADC using autonomous analog control.
*   Sets up interrupt masks and enables autonomous operation.
*
* Parameters:
*   none
*
* Return:
*   cy_rslt_t - CY_RSLT_SUCCESS if initialization successful
*
*******************************************************************************/
static cy_rslt_t init_adc(void)
{
    cy_rslt_t result;

    /* Initialize SAR ADC with autonomous analog configuration */
    result = Cy_AutAnalog_Init(&autonomous_analog_init);

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

    /* Set interrupt mask to enable SAR0 result interrupt */
    Cy_AutAnalog_SetInterruptMask(CY_AUTANALOG_INT_SAR0_RESULT);

    /* Start autonomous control of the ADC */
    Cy_AutAnalog_StartAutonomousControl();

    adc_initialized = true;

    return CY_RSLT_SUCCESS;
}
```

#### สร้างฟังก์ชัน read\_potentiometer\_mv()

```c
/*******************************************************************************
* Function Name: read_potentiometer_mv
********************************************************************************
* Summary:
*   Reads the potentiometer value from ADC and converts to millivolts.
*   Uses the autonomous analog SAR ADC API.
*
* Parameters:
*   none
*
* Return:
*   int16_t - Voltage in millivolts (0-1800 mV)
*
*******************************************************************************/
static int16_t read_potentiometer_mv(void)
{
    int32_t adc_count;
    int16_t voltage_mv;

    /* Read ADC result (raw counts) */
    adc_count = Cy_AutAnalog_SAR_ReadResult(SAR_ADC_INDEX,
                                            CY_AUTANALOG_SAR_INPUT_GPIO,
                                            SAR_ADC_CHANNEL);

    /* Convert ADC counts to millivolts */
    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;
}
```

#### สร้างฟังก์ชัน get\_pot\_percentage()

```c
/*******************************************************************************
* Function Name: get_pot_percentage
********************************************************************************
* Summary:
*   Converts potentiometer voltage to percentage (0-100%).
*   Maps the voltage range (0 to VREF_MV) to percentage scale.
*
* 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;

    /* Ensure voltage is within valid range */
    if (voltage_mv < 0)
    {
        voltage_mv = 0;
    }
    else if (voltage_mv > SAR_ADC_VREF_MV)
    {
        voltage_mv = SAR_ADC_VREF_MV;
    }

    /* Calculate percentage: (voltage / VREF) * 100 */
    percentage = ((int32_t)voltage_mv * 100) / SAR_ADC_VREF_MV;

    return (uint8_t)percentage;
}
```

#### ปรับปรุง main() ใหม่

```c
int main(void)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;
    int16_t voltage_mv;
    uint8_t percentage;

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

    /* Board initialization failed. Stop program execution. */
    if (CY_RSLT_SUCCESS != result)
    {
        handle_app_error();
    }

    /* Enable global interrupts */
    __enable_irq();

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

    /* \x1b[2J\x1b[;H - ANSI ESC sequence for clear screen. */
    printf("\x1b[2J\x1b[;H");
    printf("***********************************************************\r\n");
    printf("            PSOC Edge MCU: Potentiometer ADC               \r\n");
    printf("***********************************************************\r\n\n");

    /* Initialize SAR ADC using helper function */
    result = init_adc();

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

    /* Inform user about potentiometer connection */
    printf("ADC initialized successfully!\r\n");
    printf("Reading potentiometer on pin P15_1\r\n");
    printf("VREF = %d mV (12-bit resolution)\r\n\n", SAR_ADC_VREF_MV);

    /* CY_CM55_APP_BOOT_ADDR must be updated if CM55 memory layout is changed.*/
    Cy_SysEnableCM55(MXCM55, CY_CM55_APP_BOOT_ADDR, CM55_BOOT_WAIT_TIME_USEC);

    for(;;)
    {
        /* Read potentiometer voltage using helper function */
        voltage_mv = read_potentiometer_mv();

        /* Convert to percentage using helper function */
        percentage = get_pot_percentage(voltage_mv);

        /* Print ADC output in millivolts and percentage */
        printf("POT: %4d mV  |  %3d%%\r\n", voltage_mv, percentage);

        /* Toggle user LED to indicate activity */
        Cy_GPIO_Inv(CYBSP_USER_LED_PORT, CYBSP_USER_LED_PIN);

        /* Delay between ADC readings */
        Cy_SysLib_Delay(ADC_READ_INTERVAL_MS);
    }

}
```

#### ตัวอย่าง Output บน Serial Terminal

```bash
***********************************************************
            PSOC Edge MCU: Potentiometer ADC               
***********************************************************

ADC initialized successfully!
Reading potentiometer on pin P15_1
VREF = 1800 mV (12-bit resolution)

POT:    0 mV  |    0%
POT:  450 mV  |   25%
POT:  900 mV  |   50%
POT: 1350 mV  |   75%
POT: 1800 mV  |  100%
```

### ADC Potentiometer Flowcharts

#### Overall Program Flow and init\_adc() Flowchart

<figure><img src="/files/5O0uXbEopzDcMZigeRIg" alt=""><figcaption></figcaption></figure>

***

#### read\_potentiometer\_mv() Flowchart

```bash
┌─────────────────────────────────────────────────────────────────┐
│                read_potentiometer_mv() Function                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌──────────────────┐                                          │
│   │      START       │                                          │
│   └────────┬─────────┘                                          │
│            │                                                    │
│            ▼                                                    │
│   ┌──────────────────────────────────────┐                      │
│   │  adc_count = Cy_AutAnalog_SAR_       │                      │
│   │     ReadResult(                      │                      │
│   │       SAR_ADC_INDEX,                 │                      │
│   │       CY_AUTANALOG_SAR_INPUT_GPIO,   │                      │
│   │       SAR_ADC_CHANNEL                │                      │
│   │     )                                │                      │
│   └────────┬─────────────────────────────┘                      │
│            │                                                    │
│            │  adc_count = 0 ~ 4095 (12-bit)                     │
│            ▼                                                    │
│   ┌──────────────────────────────────────┐                      │
│   │  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,    ◄── 1800   │                      │
│   │       adc_count                      │                      │
│   │     )                                │                      │
│   └────────┬─────────────────────────────┘                      │
│            │                                                    │
│            │  voltage_mv = 0 ~ 1800 mV                          │
│            ▼                                                    │
│   ┌──────────────────┐                                          │
│   │ return voltage_mv│                                          │
│   └──────────────────┘                                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

***

#### get\_pot\_percentage() Flowchart

```bash
┌─────────────────────────────────────────────────────────────────┐
│                 get_pot_percentage() Function                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌──────────────────┐                                          │
│   │  START           │                                          │
│   │  Input: voltage  │                                          │
│   └────────┬─────────┘                                          │
│            │                                                    │
│            ▼                                                    │
│   ┌──────────────────────────────────────┐                      │
│   │         voltage_mv < 0 ?             │                      │
│   └────────┬──────────────────┬──────────┘                      │
│            │ YES              │ NO                              │
│            ▼                  ▼                                 │
│   ┌──────────────────┐  ┌──────────────────────────────────┐    │
│   │ voltage_mv = 0   │  │      voltage_mv > 1800 ?         │    │
│   └────────┬─────────┘  └────────┬──────────────┬──────────┘    │
│            │                     │ YES          │ NO            │
│            │                     ▼              │               │
│            │            ┌──────────────────┐    │               │
│            │            │voltage_mv = 1800 │    │               │
│            │            └────────┬─────────┘    │               │
│            │                     │              │               │
│            └─────────────────────┴──────────────┘               │
│                                  │                              │
│                                  ▼                              │
│            ┌─────────────────────────────────────────┐          │
│            │                                         │          │
│            │  percentage = (voltage_mv × 100)        │          │
│            │                ─────────────────        │          │
│            │                  VREF (1800)            │          │
│            │                                         │          │
│            └────────────────────┬────────────────────┘          │
│                                 │                               │
│                                 ▼                               │
│            ┌──────────────────────────────────┐                 │
│            │  return (uint8_t) percentage     │                 │
│            │         (0 ~ 100%)               │                 │
│            └──────────────────────────────────┘                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

***

#### ADC Conversion Diagram

```bash
┌─────────────────────────────────────────────────────────────────┐
│                    ADC Conversion Process                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Potentiometer (P15_1)                                         │
│        │                                                        │
│        │  Analog Voltage                                        │
│        │  (0V ~ 1.8V)                                           │
│        ▼                                                        │
│   ┌──────────────────┐                                          │
│   │    SAR ADC       │                                          │
│   │   12-bit         │                                          │
│   │   Resolution     │                                          │
│   └────────┬─────────┘                                          │
│            │                                                    │
│            │  Digital Count                                     │
│            │  (0 ~ 4095)                                        │
│            ▼                                                    │
│   ┌──────────────────────────────────────┐                      │
│   │  CountsTo_mVolts()                   │                      │
│   │                                      │                      │
│   │  mV = (count × VREF) / 4096          │                      │
│   │     = (count × 1800) / 4096          │                      │
│   │                                      │                      │
│   └────────┬─────────────────────────────┘                      │
│            │                                                    │
│            │  Voltage in mV                                     │
│            │  (0 ~ 1800 mV)                                     │
│            ▼                                                    │
│   ┌──────────────────────────────────────┐                      │
│   │  get_pot_percentage()                │                      │
│   │                                      │                      │
│   │  % = (mV × 100) / 1800               │                      │
│   │                                      │                      │
│   └────────┬─────────────────────────────┘                      │
│            │                                                    │
│            │  Percentage                                        │
│            │  (0% ~ 100%)                                       │
│            ▼                                                    │
│   ┌──────────────────┐                                          │
│   │  Display Output  │                                          │
│   │  "POT: 900 mV |  │                                          │
│   │        50%"      │                                          │
│   └──────────────────┘                                          │
│                                                                 │
│   ═══════════════════════════════════════════════════════════   │
│                                                                 │
│   Examples:                                                     │
│   ─────────                                                     │
│   Count = 0    → 0 mV    → 0%                                   │
│   Count = 1024 → 450 mV  → 25%                                  │
│   Count = 2048 → 900 mV  → 50%                                  │
│   Count = 3072 → 1350 mV → 75%                                  │
│   Count = 4095 → 1800 mV → 100%                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

***

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

```c
/*******************************************************************************
* File Name        : main.c
*
* Description      : This source file contains the main routine for non-secure
*                    application in the CM33 CPU
*
*******************************************************************************/

/*******************************************************************************
* Header Files
*******************************************************************************/

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

/*******************************************************************************
 * Macros
 ******************************************************************************/
#define CM55_BOOT_WAIT_TIME_USEC    (10U)
#define ADC_READ_INTERVAL_MS        (100U)
#define SAR_ADC_INDEX               (0U)
#define SAR_ADC_SEQUENCER           (0U)
#define SAR_ADC_CHANNEL             (0U)
#define SAR_ADC_VREF_MV             (1800U)

/*******************************************************************************
* Global Variables
*******************************************************************************/
static bool adc_initialized = false;

/*******************************************************************************
* 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);

/*******************************************************************************
* Function Name: init_adc
********************************************************************************
* Summary:
*   Initializes the SAR ADC using autonomous analog control.
*   Sets up interrupt masks and enables autonomous operation.
*
* Parameters:
*   none
*
* Return:
*   cy_rslt_t - CY_RSLT_SUCCESS if initialization successful
*
*******************************************************************************/
static cy_rslt_t init_adc(void)
{
    cy_rslt_t result;

    /* Initialize SAR ADC with autonomous analog configuration */
    result = Cy_AutAnalog_Init(&autonomous_analog_init);

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

    /* Set interrupt mask to enable SAR0 result interrupt */
    Cy_AutAnalog_SetInterruptMask(CY_AUTANALOG_INT_SAR0_RESULT);

    /* Start autonomous control of the ADC */
    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.
*   Uses the autonomous analog SAR ADC API.
*
* Parameters:
*   none
*
* Return:
*   int16_t - Voltage in millivolts (0-1800 mV)
*
*******************************************************************************/
static int16_t read_potentiometer_mv(void)
{
    int32_t adc_count;
    int16_t voltage_mv;

    /* Read ADC result (raw counts) */
    adc_count = Cy_AutAnalog_SAR_ReadResult(SAR_ADC_INDEX,
                                            CY_AUTANALOG_SAR_INPUT_GPIO,
                                            SAR_ADC_CHANNEL);

    /* Convert ADC counts to millivolts */
    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%).
*   Maps the voltage range (0 to VREF_MV) to percentage scale.
*
* 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;

    /* Ensure voltage is within valid range */
    if (voltage_mv < 0)
    {
        voltage_mv = 0;
    }
    else if (voltage_mv > SAR_ADC_VREF_MV)
    {
        voltage_mv = SAR_ADC_VREF_MV;
    }

    /* Calculate percentage: (voltage / VREF) * 100 */
    percentage = ((int32_t)voltage_mv * 100) / SAR_ADC_VREF_MV;

    return (uint8_t)percentage;
}

/*******************************************************************************
* Function Name: main
*******************************************************************************
* Summary:
*   Main function - entry point for the ADC potentiometer demo.
*
*   This demo reads the potentiometer connected to P15_1 and displays:
*   - Raw voltage in millivolts (0-1800 mV)
*   - Percentage value (0-100%)
*
*   The LED toggles with each ADC reading to indicate activity.
*
* Parameters:
*   none
*
* Return:
*   int
*
******************************************************************************/
int main(void)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;
    int16_t voltage_mv;
    uint8_t percentage;

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

    /* Board initialization failed. Stop program execution. */
    if (CY_RSLT_SUCCESS != result)
    {
        handle_app_error();
    }

    /* Enable global interrupts */
    __enable_irq();

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

    /* \x1b[2J\x1b[;H - ANSI ESC sequence for clear screen. */
    printf("\x1b[2J\x1b[;H");
    printf("***********************************************************\r\n");
    printf("            PSOC Edge MCU: Potentiometer ADC               \r\n");
    printf("***********************************************************\r\n\n");

    /* Initialize SAR ADC using helper function */
    result = init_adc();

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

    /* Inform user about potentiometer connection */
    printf("ADC initialized successfully!\r\n");
    printf("Reading potentiometer on pin P15_1\r\n");
    printf("VREF = %d mV (12-bit resolution)\r\n\n", SAR_ADC_VREF_MV);

    /* CY_CM55_APP_BOOT_ADDR must be updated if CM55 memory layout is changed.*/
    Cy_SysEnableCM55(MXCM55, CY_CM55_APP_BOOT_ADDR, CM55_BOOT_WAIT_TIME_USEC);

    for(;;)
    {
        /* Read potentiometer voltage using helper function */
        voltage_mv = read_potentiometer_mv();

        /* Convert to percentage using helper function */
        percentage = get_pot_percentage(voltage_mv);

        /* Print ADC output in millivolts and percentage */
        printf("POT: %4d mV  |  %3d%%\r\n", voltage_mv, percentage);

        /* Toggle user LED to indicate activity */
        Cy_GPIO_Inv(CYBSP_USER_LED_PORT, CYBSP_USER_LED_PIN);

        /* Delay between ADC readings */
        Cy_SysLib_Delay(ADC_READ_INTERVAL_MS);
    }

}

/* [] END OF FILE */
```

***

#### ✍️ Exercise

1. **LED Brightness Indicator** : ใช้ POT ควบคุมความเร็วการกระพริบ (Blink Rate) ของ LED

* 0-25%: Blink Rate --> 1000 ms&#x20;
* 25-50%: Blink Rate --> 500 ms
* 50-75%: Blink Rate --> 250 ms
* 75-100%: Blink Rate --> 100 ms

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

ตัวอย่าง

```c
uint8_t pot_pct = get_pot_percentage(); 
uint32_t blink_delay;

if (pot_pct < 25) { 
    blink_delay = 1000; /* Slow blink */ } 
else if (pot_pct < 50) {
.
.
. 
} else {
...
}
```

{% endhint %}

2. **Threshold Alert** : แจ้งเตือนเมื่อ POT เกิน threshold ที่กำหนด

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

ตัวอย่าง

```c
#define THRESHOLD_PCT   (75U)
static bool alert_triggered = false;

for(;;)
{
    uint8_t pot_pct = get_pot_percentage();

    if (pot_pct >= THRESHOLD_PCT && !alert_triggered)
    {
        .
        .
        alert_triggered = true;
    }
    else if (pot_pct < THRESHOLD_PCT && alert_triggered)
    {
        .
        .
        alert_triggered = false;
    }

    Cy_SysLib_Delay(100);
}
```

{% 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/potentiometer-adc.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.
