# C in ModusToolBox (MTB)

## 1. FreeRTOS: Real-Time Operating System

### 1.1 RTOS คืออะไร?

**WHY: ทำไมต้องรู้?**

* **ปัญหา:** โปรแกรมแบบ bare-metal (while loop เดียว) จัดการหลายงานพร้อมกันยาก
* **ประโยชน์:** แบ่งงานเป็น Tasks, จัดการ timing, ใช้ resources ร่วมกันได้
* **Hardware:** MCU ยุคใหม่มี RAM เพียงพอสำหรับ RTOS overhead

```shellscript
┌─────────────────────────────────────────────────────────────┐
│                      Bare-metal                             │
│  while(1) {                                                 │
│      read_sensor();    // ถ้านานเกินไป...                     │
│      process_data();   // ...งานอื่นต้องรอ                     │
│      send_to_cloud();  // blocking!                         │
│  }                                                          │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                       FreeRTOS                              │
│  Task 1: read_sensor()      ─┐                              │
│  Task 2: process_data()      ├─→ ทำงานพร้อมกัน!               │
│  Task 3: send_to_cloud()    ─┘   (time-slicing)             │
└─────────────────────────────────────────────────────────────┘
```

### 1.2 FreeRTOS Configuration

จาก `FreeRTOSConfig.h`:

```c
#define configUSE_PREEMPTION            1          // Preemptive scheduling
#define configTICK_RATE_HZ              1000       // 1ms per tick
#define configMAX_PRIORITIES            7          // 7 priority levels
#define configMINIMAL_STACK_SIZE        256        // 256 words minimum
#define configTOTAL_HEAP_SIZE           (50*1024)  // 50KB heap
#define configUSE_TICKLESS_IDLE         2          // Power saving
#define configENABLE_FPU                1          // Enable FPU
```

**HOW: ประยุกต์ใช้จริงในอุตสาหกรรม**

* **Smart Watch:** Task แยก: UI, Heart Rate, Step Counter, BLE
* **Industrial PLC:** Task แยก: I/O Scan, Communication, Control Loop
* **IoT Gateway:** Task แยก: Sensor Reading, Data Processing, Cloud Upload

**CAUTION: ข้อควรระวัง**

| ข้อผิดพลาด            | ผลกระทบ                      | วิธีป้องกัน                         |
| --------------------- | ---------------------------- | ----------------------------------- |
| Stack size น้อยเกินไป | Stack overflow, Hard fault   | ใช้ `uxTaskGetStackHighWaterMark()` |
| Heap เต็ม             | Task create fail             | Monitor heap usage                  |
| Priority inversion    | High priority task ถูก block | ใช้ mutex with priority inheritance |

### 1.3 การสร้าง Task

**WHY: ทำไมต้องรู้?**

* **ปัญหา:** งาน periodic (เช่น อ่าน sensor ทุก 100ms) ต้องจัดการ timing
* **ประโยชน์:** RTOS จัดการ scheduling ให้, โค้ดอ่านง่าย
* **Hardware:** Kernel ใช้ SysTick timer จัดการ context switching

**ตัวอย่างโค้ด**

**Header file (`sensor_hub_daq_task.h`):**

```c
#define TASK_SENSOR_HUB_DAQ_PRIORITY    (configMAX_PRIORITIES - 1)  // High priority
#define TASK_SENSOR_HUB_DAQ_STACK_SIZE  (2048u)  // Stack size in words
#define TASK_SENSOR_HUB_DAQ_DELAY_MS    (10u)    // Task period

cy_rslt_t create_sensor_hub_daq_task(void);
```

**Task function:**

```c
static void sensor_hub_daq_task(void *pvParameters)
{
    // ===== One-time Initialization =====
    // Initialize I2C, sensor, etc.

    TickType_t xLastWakeTime = xTaskGetTickCount();
    const TickType_t xDelay = 100 / portTICK_PERIOD_MS;  // 100ms

    // ===== Infinite Loop =====
    for (;;)
    {
        // 1. อ่านค่าจากเซนเซอร์
        mtb_bmi270_read(&bmi270, &bmi270_data);

        // 2. แปลงและแสดงผล
        float accel_x = lsb_to_mps2(bmi270_data.sensor_data.acc.x, ...);
        printf("Accel X: %f m/s²\r\n", accel_x);

        // 3. Toggle LED
        Cy_GPIO_Inv(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN);

        // 4. Wait for next cycle (NON-BLOCKING!)
        vTaskDelayUntil(&xLastWakeTime, xDelay);
    }
}
```

**Task creation:**

```c
cy_rslt_t create_sensor_hub_daq_task(void)
{
    BaseType_t status;

    status = xTaskCreate(
        sensor_hub_daq_task,              // Task function
        "Sensor Hub DAQ",                 // Task name (for debug)
        TASK_SENSOR_HUB_DAQ_STACK_SIZE,   // Stack size
        NULL,                             // Parameter (optional)
        TASK_SENSOR_HUB_DAQ_PRIORITY,     // Priority
        NULL                              // Task handle (optional)
    );

    return (pdPASS == status) ? CY_RSLT_SUCCESS : CY_RSLT_ERROR;
}
```

**HOW: ประยุกต์ใช้จริงในอุตสาหกรรม**

* **Sensor Data Acquisition:** อ่านค่าทุก 10-100ms
* **Motor Control:** PID loop ทุก 1ms
* **Communication:** Check incoming data ทุก 50ms

**CAUTION: ข้อควรระวัง**

| ข้อผิดพลาด                             | ผลกระทบ                     | วิธีป้องกัน                           |
| -------------------------------------- | --------------------------- | ------------------------------------- |
| ใช้ `vTaskDelay` แทน `vTaskDelayUntil` | Timing drift                | ใช้ `vTaskDelayUntil` สำหรับ periodic |
| Task ไม่มี delay                       | CPU 100%, task อื่นไม่ทำงาน | ต้องมี delay หรือ yield               |
| Stack overflow                         | Crash, Data corruption      | ตรวจสอบ high watermark                |

### 1.4 vTaskDelay vs vTaskDelayUntil

```shellscript
vTaskDelay(100):
├─ Work (20ms) ─┤ Delay 100ms ├─ Work (20ms) ─┤ Delay 100ms ├─
│               ←── 120ms ──→ │               ←── 120ms ──→ │
                    ↑ Timing Drift!

vTaskDelayUntil(100):
├─ Work (20ms) ─┤ Delay 80ms ├─ Work (20ms) ─┤ Delay 80ms ├─
│               ←── 100ms ──→ │               ←── 100ms ──→ │
                    ↑ Precise Timing
```

***

## 2. I2C Communication

### 2.1 I2C คืออะไร?

**WHY: ทำไมต้องรู้?**

* **ปัญหา:** ต้องเชื่อมต่อกับ sensor/peripheral ภายนอกที่มี protocol ซับซ้อน
* **ประโยชน์:** ใช้สายแค่ 2 เส้น (SDA, SCL), เชื่อมต่อหลาย device ได้
* **Hardware:** Sensor ส่วนใหญ่รองรับ I2C (เช่น IMU, Temperature, Display)

```ini
     MCU (Master)                    Sensors (Slaves)
    ┌───────────┐                  ┌──────────────┐
    │           │───── SCL ────────│ BMI270 (0x68)│
    │   I2C     │                  └──────────────┘
    │ Controller│───── SDA ────────┬──────────────┐
    │           │                  │ SHT31 (0x44) │
    └───────────┘                  └──────────────┘
                                    (หลาย device บน bus เดียว)
```

### 2.2 I2C Initialization

**ตัวอย่างโค้ด**

```c
static mtb_hal_i2c_t CYBSP_I2C_CONTROLLER_hal_obj;
static cy_stc_scb_i2c_context_t CYBSP_I2C_CONTROLLER_context;

// Step 1: Initialize I2C peripheral
initStatus = Cy_SCB_I2C_Init(CYBSP_I2C_CONTROLLER_HW,
                             &CYBSP_I2C_CONTROLLER_config,
                             &CYBSP_I2C_CONTROLLER_context);
if (CY_SCB_I2C_SUCCESS != initStatus) {
    handle_app_error();
}

// Step 2: Enable I2C
Cy_SCB_I2C_Enable(CYBSP_I2C_CONTROLLER_HW);

// Step 3: Setup HAL wrapper
result = mtb_hal_i2c_setup(&CYBSP_I2C_CONTROLLER_hal_obj,
                           &CYBSP_I2C_CONTROLLER_hal_config,
                           &CYBSP_I2C_CONTROLLER_context,
                           NULL);
```

**HOW: ประยุกต์ใช้จริงในอุตสาหกรรม**

* **Smart Watch:** I2C bus เชื่อม IMU, Heart Rate, Touch Controller
* **Weather Station:** I2C เชื่อม Temperature, Humidity, Pressure sensors
* **OLED Display:** SSD1306 display ใช้ I2C

**CAUTION: ข้อควรระวัง**

| ข้อผิดพลาด             | ผลกระทบ            | วิธีป้องกัน                    |
| ---------------------- | ------------------ | ------------------------------ |
| ไม่มี Pull-up resistor | Communication fail | ใช้ external 4.7kΩ pull-up     |
| Address conflict       | Device ชนกัน       | ตรวจสอบ address แต่ละ device   |
| Clock speed ไม่ตรง     | Data corruption    | ใช้ speed ที่ทุก device รองรับ |
| Bus stuck (SDA low)    | I2C หยุดทำงาน      | Implement bus recovery         |

***

## 3. BMI270 IMU Sensor Integration

### 3.1 BMI270 คืออะไร?

**BMI270** = 6-axis Inertial Measurement Unit (IMU) จาก Bosch

* **Accelerometer:** วัดความเร่ง 3 แกน (X, Y, Z) หน่วย g หรือ m/s²
* **Gyroscope:** วัดความเร็วเชิงมุม 3 แกน หน่วย °/s หรือ rad/s

```ini
               +Y
                ↑
                │
                │  ┌──────────┐
                │  │  BMI270  │
        +X ←────┼──│          │
                │  │    ●     │ ← Sensor
                │  └──────────┘
                │
               +Z (out of page)
```

### 3.2 Sensor Initialization

**ตัวอย่างโค้ด**

```c
static mtb_bmi270_t bmi270;
static mtb_bmi270_data_t bmi270_data;

// Step 1: Initialize sensor via I2C
result = mtb_bmi270_init_i2c(&bmi270,
                             &CYBSP_I2C_CONTROLLER_hal_obj,
                             MTB_BMI270_ADDRESS_DEFAULT);  // 0x68
if (CY_RSLT_SUCCESS != result) {
    handle_app_error();
}

// Step 2: Configure with default settings
result = mtb_bmi270_config_default(&bmi270);
if (CY_RSLT_SUCCESS != result) {
    handle_app_error();
}
```

### 3.3 Reading Sensor Data

```c
// อ่านค่าจากเซนเซอร์
result = mtb_bmi270_read(&bmi270, &bmi270_data);

// ค่าดิบที่ได้ (int16_t):
// bmi270_data.sensor_data.acc.x  ← Accelerometer X
// bmi270_data.sensor_data.acc.y  ← Accelerometer Y
// bmi270_data.sensor_data.acc.z  ← Accelerometer Z
// bmi270_data.sensor_data.gyr.x  ← Gyroscope X
// bmi270_data.sensor_data.gyr.y  ← Gyroscope Y
// bmi270_data.sensor_data.gyr.z  ← Gyroscope Z
```

**HOW: ประยุกต์ใช้จริงในอุตสาหกรรม**

* **Fitness Tracker:** นับก้าว, ตรวจจับกิจกรรม (วิ่ง, ว่ายน้ำ)
* **Drone:** ควบคุม stability และ orientation
* **Gaming Controller:** ตรวจจับการเคลื่อนไหวมือ
* **Industrial:** ตรวจจับ vibration เพื่อ predictive maintenance

**CAUTION: ข้อควรระวัง**

| ข้อผิดพลาด           | ผลกระทบ                      | วิธีป้องกัน                 |
| -------------------- | ---------------------------- | --------------------------- |
| ไม่ calibrate sensor | ค่า offset ผิด               | Calibrate ก่อนใช้งาน        |
| อ่านค่าถี่เกินไป     | ได้ค่าซ้ำ                    | ใช้ Data Ready interrupt    |
| Range ไม่เหมาะสม     | Clipping หรือ Resolution ต่ำ | เลือก range ตาม application |

## 4. Math Operations สำหรับ Sensor Data

### 4.1 การแปลงหน่วย (Unit Conversion)

```c
/* จาก sensor_hub_daq_task.c */

#define GRAVITY_EARTH  (9.80665f)  /* m/s² */
#define DEG_TO_RAD     (0.01745f)  /* π/180 */

/* แปลง raw accelerometer → m/s² */
static float lsb_to_mps2(int16_t val, int8_t g_range, uint8_t bit_width)
{
    /*
     * สูตร: acc = (raw_value × g_range × 9.80665) / 2^(bit_width-1)
     *
     * Parameters:
     * - val: raw value จาก sensor (-32768 to 32767)
     * - g_range: ช่วงวัด (2 = ±2g)
     * - bit_width: 16 bits
     *
     * Example: val=16384, g_range=2, bit_width=16
     * half_scale = 2^15 = 32768
     * result = (9.80665 × 16384 × 2) / 32768 = 9.80665 m/s²
     */

    float half_scale = (float)(1u << (bit_width - 1u));
    return ((GRAVITY_EARTH) * val * g_range) / half_scale;
}

/* แปลง raw gyroscope → rad/s */
static float lsb_to_rps(int16_t val, float dps, uint8_t bit_width)
{
    /*
     * สูตร: gyro = (raw × dps × π/180) / 2^(bit_width-1)
     *
     * Parameters:
     * - val: raw value
     * - dps: degrees per second range (2000)
     * - bit_width: 16 bits
     */

    float half_scale = (float)(1u << (bit_width - 1u));
    return ((DEG_TO_RAD) * ((dps) / (half_scale)) * (val));
}
```

### 4.2 Vector Magnitude

```c
#include <math.h>  /* sqrtf, fabsf */

/* คำนวณขนาดของ vector */
static float calculate_magnitude(float x, float y, float z)
{
    return sqrtf(x * x + y * y + z * z);
}

/*
 * Magnitude ของ acceleration:
 * - วางราบ: sqrt(0² + 0² + 9.81²) ≈ 9.81 m/s² (1g)
 * - เขย่า: magnitude จะเพิ่มขึ้น
 * - ตกอิสระ: magnitude ≈ 0 (weightlessness)
 */

/* ตรวจจับการเคลื่อนไหว */
float mag = calculate_magnitude(acc_x, acc_y, acc_z);
float deviation = fabsf(mag - GRAVITY_EARTH);

if (deviation > MOTION_THRESHOLD)
{
    /* Motion detected! */
}
```

### 4.3 Absolute Value

```c
#include <stdlib.h>  /* abs() for int */
#include <math.h>    /* fabsf() for float */

/* Integer absolute */
int16_t raw = -1000;
int16_t abs_raw = abs(raw);  /* 1000 */

/* Float absolute */
float deviation = -0.5f;
float abs_dev = fabsf(deviation);  /* 0.5f */

/* จากโค้ด orientation detection */
abs_x = abs(bmi270_data.sensor_data.acc.x);
abs_y = abs(bmi270_data.sensor_data.acc.y);
abs_z = abs(bmi270_data.sensor_data.acc.z);

/* หาแกนที่มีค่ามากที่สุด */
if ((abs_z > abs_x) && (abs_z > abs_y))
{
    /* Z-axis is dominant */
}
```

***

## 5. Enum - State Machines

### 5.1 Enum Basics

```c
/* Enum = ชุดของค่าคงที่ที่ตั้งชื่อ */

typedef enum {
    MOTION_STATIONARY = 0,  /* ค่าเริ่มต้น 0 */
    MOTION_LIGHT,           /* = 1 (อัตโนมัติ) */
    MOTION_MODERATE,        /* = 2 */
    MOTION_INTENSE          /* = 3 */
} motion_state_t;

/* ใช้งาน */
motion_state_t current_state = MOTION_STATIONARY;

if (current_state == MOTION_INTENSE)
{
    /* Handle intense motion */
}

/* Switch-case กับ enum */
switch (current_state)
{
    case MOTION_STATIONARY:
        printf("Device is still\n");
        break;
    case MOTION_LIGHT:
        printf("Light movement\n");
        break;
    case MOTION_MODERATE:
    case MOTION_INTENSE:
        printf("Significant motion!\n");
        break;
}
```

### 5.2 Enum สำหรับ Orientation

```c
/* จาก sensor-hub-imu concept */

typedef enum {
    ORIENTATION_UNKNOWN = 0,
    ORIENTATION_UP,         /* Screen facing up */
    ORIENTATION_DOWN,       /* Screen facing down */
    ORIENTATION_LEFT,       /* Left edge down */
    ORIENTATION_RIGHT,      /* Right edge down */
    ORIENTATION_TOP,        /* Top edge down */
    ORIENTATION_BOTTOM      /* Bottom edge down */
} orientation_t;

orientation_t detect_orientation(float ax, float ay, float az)
{
    float abs_x = fabsf(ax);
    float abs_y = fabsf(ay);
    float abs_z = fabsf(az);

    if ((abs_z > abs_x) && (abs_z > abs_y))
    {
        return (az > 0) ? ORIENTATION_UP : ORIENTATION_DOWN;
    }
    else if ((abs_y > abs_x) && (abs_y > abs_z))
    {
        return (ay > 0) ? ORIENTATION_BOTTOM : ORIENTATION_TOP;
    }
    else
    {
        return (ax > 0) ? ORIENTATION_LEFT : ORIENTATION_RIGHT;
    }
}
```

***

## 6. Memory Management

### 6.1 memset - ล้างข้อมูล

```c
#include <string.h>  /* memset, memcpy */

/* ล้าง struct ให้เป็น 0 */
motion_stats_t stats;
memset(&stats, 0, sizeof(motion_stats_t));

/* ล้าง array */
float buffer[100];
memset(buffer, 0, sizeof(buffer));

/* Syntax: memset(destination, value, size_in_bytes) */
/* value ส่วนใหญ่ใช้ 0 */
```

### 6.2 memcpy - Copy ข้อมูล

```c
/* Copy struct */
imu_data_t source = {.acc_x = 100, .acc_y = 200, .acc_z = 300};
imu_data_t dest;

memcpy(&dest, &source, sizeof(imu_data_t));
/* dest ตอนนี้เหมือน source ทุกประการ */

/* Copy array */
float src_buffer[10] = {1.0f, 2.0f, 3.0f, /*...*/};
float dst_buffer[10];

memcpy(dst_buffer, src_buffer, sizeof(src_buffer));
```

### 6.3 sizeof - ขนาดของ Type/Variable

```c
/* sizeof type */
size_t int_size = sizeof(int);              /* 4 */
size_t float_size = sizeof(float);          /* 4 */
size_t ptr_size = sizeof(void *);           /* 4 (32-bit) or 8 (64-bit) */

/* sizeof variable */
imu_data_t data;
size_t struct_size = sizeof(data);          /* อาจมี padding */
size_t struct_size2 = sizeof(imu_data_t);   /* เหมือนกัน */

/* sizeof array */
int arr[10];
size_t arr_bytes = sizeof(arr);             /* 40 bytes (10 × 4) */
size_t arr_count = sizeof(arr) / sizeof(arr[0]);  /* 10 elements */
```

***

### สรุปองค์ความรู้สำคัญ

#### API Functions ที่ใช้บ่อย

<table><thead><tr><th width="100">ประเภท</th><th>Function</th><th>คำอธิบาย</th></tr></thead><tbody><tr><td><strong>RTOS</strong></td><td><code>xTaskCreate()</code></td><td>สร้าง Task</td></tr><tr><td></td><td><code>vTaskDelayUntil()</code></td><td>Delay แบบ precise</td></tr><tr><td></td><td><code>xTaskGetTickCount()</code></td><td>อ่านค่า tick ปัจจุบัน</td></tr><tr><td></td><td><code>vTaskStartScheduler()</code></td><td>เริ่ม RTOS</td></tr><tr><td><strong>I2C</strong></td><td><code>Cy_SCB_I2C_Init()</code></td><td>Initialize I2C</td></tr><tr><td></td><td><code>mtb_hal_i2c_setup()</code></td><td>Setup HAL</td></tr><tr><td><strong>BMI270</strong></td><td><code>mtb_bmi270_init_i2c()</code></td><td>Initialize sensor</td></tr><tr><td></td><td><code>mtb_bmi270_config_default()</code></td><td>Configure sensor</td></tr><tr><td></td><td><code>mtb_bmi270_read()</code></td><td>อ่านค่า</td></tr></tbody></table>

## Quick Reference

### Struct

```c
typedef struct {
    int16_t x, y, z;
} vector3i_t;

vector3i_t v = {.x = 1, .y = 2, .z = 3};
vector3i_t *ptr = &v;
ptr->x = 10;  /* Arrow operator */
```

### Pointer

```c
int value = 42;
int *ptr = &value;    /* ptr = address of value */
*ptr = 100;           /* Modify through pointer */

void func(data_t *out) { *out = result; }
func(&my_data);
```

### Array

```c
float buf[10] = {0};
size_t len = sizeof(buf) / sizeof(buf[0]);
index = (index + 1) % BUFFER_SIZE;  /* Circular */
```

### Math

```c
#include <math.h>
float mag = sqrtf(x*x + y*y + z*z);
float abs_val = fabsf(value);
```

### Memory

```c
memset(&struct_var, 0, sizeof(struct_var));
memcpy(&dest, &src, sizeof(src));
```

### Enum

```c
typedef enum { STATE_A, STATE_B, STATE_C } state_t;
state_t current = STATE_A;
switch (current) { case STATE_A: /*...*/ break; }
```

***


---

# 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/sensor-interfacing/c-in-modustoolbox-mtb.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.
