๐ English Abstract
This technical article explores strategies for minimizing communication jitter in high-speed EtherCAT slave nodes built with STM32 microcontrollers and the LAN9252 ESC. It details the optimization of the SOES (Simple Open EtherCAT Slave) stack and the implementation of SPI DMA double-buffering architecture. Readers will gain actionable insights into resolving real-time interrupt delays, handling D-Cache coherency issues, and stabilizing microsecond-level synchronization.
์ฐ์ ์ฉ ์๋ํ ๋ฐ ๋ก๋ด ์ ์ด ์์คํ ์์ EtherCAT (Ethernet for Control Automation Technology) ํต์ ์ ํ์ด์๋ ์ค์๊ฐ ์ฑ๋ฅ์ ๊ฒฐ์ ์ง๋ ํต์ฌ ๊ธฐ์ ์ ๋๋ค. ํนํ ๋ง์ดํฌ๋ก์ด(ยตs) ๋จ์์ ์งง์ ์ฃผ๊ธฐ ์๊ฐ(Cycle Time) ๋ด์์ ๋ชจํฐ ๋๋ผ์ด๋ฒ๋ ์ ์ถ๋ ฅ ๋ชจ๋์ ์ ์ดํ ๋, ์งํฐ(Jitter)๋ฅผ ์ต์ํํ๊ณ ๊ฒฐ์ ๋ก ์ (Deterministic) ํต์ ํ๊ฒฝ์ ๋ณด์ฅํ๋ ๊ฒ์ ์์คํ ์ ์ฒด์ ์์ ์ฑ๊ณผ ์ ํ๋๋ฅผ ์ข์ฐํฉ๋๋ค.
๋ณธ ํฌ์คํ ์์๋ **STM32 ๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ(MCU)**์ Microchip์ฌ์ **LAN9252 EtherCAT ์ฌ๋ ์ด๋ธ ์ปจํธ๋กค๋ฌ(EtherCAT Slave Controller, ESC)**๋ฅผ ์กฐํฉํ์ฌ ์คํ์์ค ์คํ์ธ **SOES (Simple Open EtherCAT Slave)**๋ฅผ ํ์ฌํ ๋ ๋ฐ์ํ๋ ํต์ ์งํฐ ๋ฌธ์ ์ ๊ทผ๋ณธ ์์ธ์ ๋ถ์ํฉ๋๋ค. ๋ํ, ์ด๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด **SPI DMA ์ด์ค ๋ฒํผ๋ง(Double Buffering)** ๊ธฐ์ ์ ๋์ ํ๊ณ ์ฌํ ํธ๋ฌ๋ธ์ํ ์ ์ํํ ๊ฒฝํ์ ์์ธํ ๊ณต์ ํฉ๋๋ค.
1. STM32์ LAN9252 ๊ธฐ๋ฐ EtherCAT ์ํคํ ์ฒ ๋ฐ ์งํฐ ๋ฐ์ ์์ธ
LAN9252๋ ์์ฒด์ ์ผ๋ก EtherCAT์ ๋ฌผ๋ฆฌ์ธต(PHY)๊ณผ ๋ฐ์ดํฐ ๋งํฌ ์ธต์ ์ฒ๋ฆฌํ๋ ์ ์ฉ ํ๋์จ์ด ์นฉ์ด์ง๋ง, ์ ํ๋ฆฌ์ผ์ด์ ๊ณ์ธต(Application Layer) ๋ฐ ํ๋ก์ธ์ค ๋ฐ์ดํฐ(Process Data, PD) ๊ตํ์ ์ธ๋ถ์ ํธ์คํธ ๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ(STM32)์์ ์ํ๋์ด์ผ ํฉ๋๋ค. ๋ ์ฅ์น ๊ฐ์ ์ธํฐํ์ด์ค๋ก SPI (Serial Peripheral Interface)๊ฐ ๋๋ฆฌ ์ฌ์ฉ๋ฉ๋๋ค.
์์คํ ํต์ ๊ตฌ์กฐ ๊ฐ์
์ผ๋ฐ์ ์ธ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ์ ์์๋ก ์งํ๋ฉ๋๋ค:
- EtherCAT ๋ง์คํฐ๊ฐ ํ๋ ์์ ์ ์กํ๋ฉด LAN9252๊ฐ ์ด๋ฅผ ์์ ํ๊ณ DPRAM(Dual-Port RAM)์ **ํ๋ก์ธ์ค ๋ฐ์ดํฐ(Process Data)**๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
- LAN9252์ **๋ถ์ฐ ํด๋ก(Distributed Clocks, DC)** ๋๊ธฐํ ์ ํธ์ธ
SYNC0ํ์ด ํ์ด(High)๋ก ํธ๋ฆฌ๊ฑฐ๋์ด STM32์ ์ธ๋ถ ์ธํฐ๋ฝํธ(EXTI)๋ฅผ ๋ฐ์์ํต๋๋ค. - STM32๋ ์ธํฐ๋ฝํธ ์๋น์ค ๋ฃจํด(Interrupt Service Routine, ISR) ๋ด์์ SPI ์ธํฐํ์ด์ค๋ฅผ ํตํด LAN9252์ Process Data RAM ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฐ๊ธฐ ์์ ์ ์งํํฉ๋๋ค.
์ค์๊ฐ ์งํฐ(Jitter)๊ฐ ๋ฐ์ํ๋ ํต์ฌ ์์ธ
์ฃผ๊ธฐ ์๊ฐ์ด 250ยตs ์ดํ๋ก ์์์ง ๊ฒฝ์ฐ, ์ํํธ์จ์ด ๋ธ๋กํน๊ณผ ๋ฒ์ค ๋ณ๋ชฉ ํ์์ผ๋ก ์ธํด ์ ยตs์์ ์์ญ ยตs์ ๋ฌํ๋ ์งํฐ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ฃผ์ ์์ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- SPI ํด๋ง(Polling) ๋ฐ ํด๋ง ๋๊ธฐ ์๊ฐ: CPU๊ฐ SPI ๋ฐ์ดํฐ ์ก์์ ์๋ฃ ํ๋๊ทธ๋ฅผ ๋ฃจํ๋ฌธ์ผ๋ก ๋๊ธฐํ ๊ฒฝ์ฐ ๋ค๋ฅธ ๊ณ ์ฐ์ ์์ ์์ ์ด ์ง์ฐ๋ฉ๋๋ค.
- ๋จ์ผ ๋ฒํผ(Single Buffer) ๊ฒฝ์ ์ํ(Race Condition): SOES ์คํ์ด ํ๋ก์ธ์ค ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฒ๋ฆฌํ๋ ๋์ค ๋ค์ SYNC0 ์ธํฐ๋ฝํธ๊ฐ ๋ฐ์ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒ๋ผ์ดํธ ๋๋ ๋๊ธฐ ์ง์ฐ์ด ๋ฐ์ํฉ๋๋ค.
- ์ค๋จ ์์ฒญ(Interrupt Request, IRQ) ๋ ์ดํด์: STM32์ NVIC(Nested Vectored Interrupt Controller) ์ฐ์ ์์ ์ค์ ๋ฏธ์์ผ๋ก ์ธํด SYNC0 ์ธํฐ๋ฝํธ ์ง์ ์์ ์ด ๋ฏธ์ธํ๊ฒ ์๋์น๋ ํ์์ ๋๋ค.
- ์์คํ ์บ์(Cache) ๋ถ์ผ์น: Cortex-M7(STM32F7, STM32H7 ๋ฑ) ๊ณ์ด ์ฌ์ฉ ์ D-Cache๊ฐ ํ์ฑํ๋ ์ํ์์ DMA ์ ์ก ์ ๋ฐ์ดํฐ ๋๊ธฐํ ์ง์ฐ์ด ๋ฐ์ํฉ๋๋ค.
2. SOES ์คํ ๊ตฌ์กฐ ๋ฐ SPI DMA ์ด์ค ๋ฒํผ๋ง ๊ตฌํ
SOES(Simple Open EtherCAT Slave) ์คํ์ ๊ฒฝ๋ํ๋์ด ์๋ฒ ๋๋ ์์คํ
์ ์ ํฉํ์ง๋ง, ๊ธฐ๋ณธ ์ ๊ณต๋๋ esc_hw.c ๋๋ผ์ด๋ฒ ์์ ๋ ๋๋ถ๋ถ ์ฐจ๋จํ(Blocking) SPI ํจ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด๋ฅผ ๋
ผ๋ธ๋กํน(Non-blocking) ๊ณ ์ DMA ๋ฐฉ์์ผ๋ก ์ฌ์ค๊ณํด์ผ ํฉ๋๋ค.
SPI DMA ์ด์ค ๋ฒํผ๋ง (Ping-Pong Buffer) ๋ฉ์ปค๋์ฆ
์ด์ค ๋ฒํผ๋ง์ CPU๊ฐ ํ์ฌ ์ฃผ๊ธฐ์ ํ๋ก์ธ์ค ๋ฐ์ดํฐ๋ฅผ ํด์ํ๊ณ ์ ์ด ์๊ณ ๋ฆฌ์ฆ์ ๊ณ์ฐํ๋ ๋์, DMA๋ ํ๋์จ์ด์ ์ผ๋ก ๋ค์ ์ฃผ๊ธฐ์ ๋ฐ์ดํฐ๋ฅผ SPI ๋ฒ์ค๋ฅผ ํตํด ๋ฏธ๋ฆฌ ์์ /์ก์ ํ๋๋ก ๋ง๋๋ ๊ธฐ์ ์ ๋๋ค.
+-----------------------------------------------------------------------+
| Buffer A (Ping) : [ CPU ์ ์ด ์๊ณ ๋ฆฌ์ฆ ์ฒ๋ฆฌ ์ค (Read/Write) ] |
| Buffer B (Pong) : [ SPI DMA ๊ฐ LAN9252 ์ ๋ฐ์ดํฐ ์ก์์ ์ค ] |
+-----------------------------------------------------------------------+
โ โ
โโโโโโโโโโโโโโ ๋ค์ SYNC0 ์ ํฌ์ธํฐ ์ค์ โโโโโโโโโโโโโโโ
๊ตฌํ ์ ํต์ฌ ํฌ์ธํธ๋ DMA ์ ์ก ์๋ฃ ์ฝ๋ฐฑ ํจ์(Callback)์ SYNC0 ์ธํฐ๋ฝํธ๋ฅผ ์ฒ ์ ํ ๋๊ธฐํํ๋ ๊ฒ์ ๋๋ค.
์ฃผ์ ์ฝ๋ ๊ตฌ์กฐํ ์์ (STM32 HAL ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ๋ฐ)
์๋ ๊ฐ๋ ์ฝ๋๋ ์ด์ค ๋ฒํผ ์ ์ด ์ค์ํ(Swapping) ๊ตฌ์กฐ๋ฅผ ๋ณด์ฌ์ค๋๋ค.
typedef struct {
uint8_t rx_buf[2][EC_MAX_PD_SIZE];
uint8_t tx_buf[2][EC_MAX_PD_SIZE];
volatile uint8_t active_index; // 0 or 1
volatile uint8_t dma_busy;
} EtherCAT_Buffer_t;
static EtherCAT_Buffer_t ec_buf;
// LAN9252 SYNC0 ์ธ๋ถ ์ธํฐ๋ฝํธ ํธ๋ค๋ฌ
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == Ethernet_SYNC0_Pin) {
if (!ec_buf.dma_busy) {
// 1. ๋ฒํผ ์ธ๋ฑ์ค ์ค์ (Ping-Pong)
uint8_t process_idx = ec_buf.active_index;
ec_buf.active_index ^= 1;
uint8_t dma_idx = ec_buf.active_index;
// 2. SOES ์คํ์ ์์ ๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ฒํผ ์ ๋ฌ ๋ฐ ์ฑ ๋ก์ง ์คํ
ec_apply_process_data(ec_buf.rx_buf[process_idx], ec_buf.tx_buf[process_idx]);
// 3. ๋ค์ ์ฃผ๊ธฐ๋ฅผ ์ํ SPI DMA ๋น๋๊ธฐ ์ ์ก ๊ฐ์
ec_buf.dma_busy = 1;
HAL_SPI_TransmitReceive_DMA(&hspi1,
ec_buf.tx_buf[dma_idx],
ec_buf.rx_buf[dma_idx],
EC_MAX_PD_SIZE);
} else {
// ์งํฐ ํญ์ฃผ ๋๋ DMA ๋ฏธ์๋ฃ ์ฃ์ง ์ผ์ด์ค ์ฒ๋ฆฌ (์ค๋ฒ๋ฐ ๋ฐ์)
handle_ecat_overrun_error();
}
}
}
// SPI DMA ์ ์ก ์๋ฃ ์ฝ๋ฐฑ
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
if (hspi->Instance == SPI1) {
ec_buf.dma_busy = 0; // DMA ์ ์ก ์๋ฃ ํ๋๊ทธ ํด์
}
}
3. ์ค๋ฌด ํธ๋ฌ๋ธ์ํ ๋ฐ ์ฃ์ง ์ผ์ด์ค (Edge Cases) ํด๊ฒฐ
์ด์ค ๋ฒํผ๋ง์ ์ ์ฉํ๋๋ผ๋ ์ค์ ๋ณด๋ ํ ์คํธ ํ๊ฒฝ์์๋ ์์์น ๋ชปํ ์งํฐ๋ ํต์ ์ดํ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ํ์ ์์ ์์ฃผ ์ง๋ฉดํ๋ 3๊ฐ์ง ํต์ฌ ํธ๋ฌ๋ธ์ํ ์ผ์ด์ค์ ํด๊ฒฐ์ฑ ์ ๋๋ค.
์ผ์ด์ค 1: Cortex-M7 D-Cache ์ผ๊ด์ฑ(Coherency) ๋ฌธ์
STM32F7์ด๋ STM32H7๊ณผ ๊ฐ์ ๊ณ ์ฑ๋ฅ MCU์ ๊ฒฝ์ฐ ๋ฐ์ดํฐ ์บ์(Data Cache, D-Cache)๊ฐ ํ์ฑํ๋์ด ์์ผ๋ฉด, CPU๊ฐ RAM์ ๋ฒํผ ๋ฐ์ดํฐ๋ฅผ ์์ ํ์์๋ DMA๊ฐ SRAM์ ๋ณ๊ฒฝ๋์ง ์์ ์ด์ ๋ฐ์ดํฐ๋ฅผ LAN9252๋ก ์ ์กํ๊ฑฐ๋ ๊ทธ ๋ฐ๋์ ํ์์ด ๋ฐ์ํฉ๋๋ค.
[ํด๊ฒฐ์ฑ
] DMA๊ฐ ์ ๊ทผํ๋ EtherCAT ๋ฒํผ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ MPU(Memory Protection Unit)๋ฅผ ํตํด Non-Cacheable ์์ญ์ผ๋ก ์ค์ ํ๊ฑฐ๋, DMA ์ ์ก ์ ํ๋ก SCB_CleanDCache_by_Addr() ๋ฐ SCB_InvalidateDCache_by_Addr() ์ฝ๋ฉ ๊ธฐ๋ฒ์ ์ ์ฉํด์ผ ํฉ๋๋ค.
์ผ์ด์ค 2: DC (Distributed Clock) ๋๊ธฐํ ์ดํ ๋ฐ SAFEOP ์ํ ์ ์ด
EtherCAT ๋ง์คํฐ(TwinCAT ๋๋ SOEM)๋ ์ฌ๋ ์ด๋ธ์ ๋ฐ์ดํฐ ์๋ต ์๊ฐ์ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ฒ์ฆํฉ๋๋ค. SPI ์ ์ก ์๊ฐ์ด ๋ฏธ์ธํ๊ฒ ํ๋ค๋ ค SYNC0 ๋ฐ์ ์์ ์ ์ฌ๋ฐ๋ฅธ ๋ฐ์ดํฐ๊ฐ ์ ์ก๋์ง ๋ชปํ๋ฉด ๋ง์คํฐ๋ **์์น๋ ํ์์์(Watchdog Timeout)**์ ๋ฐ์์ํค๊ณ ์ฌ๋ ์ด๋ธ ์ํ๋ฅผ OP (Operational)์์ SAFEOP๋ก ๊ฐ์ ์ ํํฉ๋๋ค.
[ํด๊ฒฐ์ฑ
] NVIC ์ธํฐ๋ฝํธ ์ฐ์ ์์ ์ต์ ํ๊ฐ ํ์์ ์
๋๋ค. SYNC0 ์ธํฐ๋ฝํธ์ ์ฐ์ ์์๋ฅผ ์์คํ
๋ด ์ต์์(Priority 0)๋ก ๋ฐฐ์ ํ๊ณ , RTOS๋ฅผ ์ฌ์ฉ ์ค์ด๋ผ๋ฉด FreeRTOS์ configMAX_SYSCALL_INTERRUPT_PRIORITY๋ณด๋ค ๋์ ์ฐ์ ์์๋ก ์ค์ ํ์ฌ RTOS ์ปค๋์ ์ํด ์ง์ฐ๋์ง ์๋๋ก ์กฐ์นํด์ผ ํฉ๋๋ค.
์ผ์ด์ค 3: LAN9252 SPI ์นฉ์ ํ(CS) ํ ํ์ด๋ฐ ์ง์ฐ
HAL ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ HAL_GPIO_WritePin() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ํํธ์จ์ด์ ์ผ๋ก CS(Chip Select) ํ์ ์ ์ดํ ๋, ๋ ์ง์คํฐ ์ง์ ์ ๊ทผ ๋ฐฉ์์ ๋นํด ์๋ฐฑ ๋๋
ธ์ด(ns)์ ์ ์ด ์ง์ฐ์ด ๋์ ๋ ์ ์์ต๋๋ค.
[ํด๊ฒฐ์ฑ
] GPIO ํ ์ ์ด ์ ์ง์ BSRR(Bit Set Reset Register) ๋ ์ง์คํฐ๋ฅผ ์กฐ์ํ๋๋ก ๋งคํฌ๋ก๋ฅผ ์ ํํฉ๋๋ค. (์: GPIOA->BSRR = GPIO_PIN_4;)
4. ์งํฐ ์ธก์ ๋ฐ ์ค์๊ฐ ์ฑ๋ฅ ๊ฒ์ฆ
๊ฐ์ ๋ ์์คํ ์ ์ต์ ํ ์ ๋ฌด๋ฅผ ๊ฒ์ฆํ๊ธฐ ์ํด ์ค์ค๋ก์ค์ฝํ ๋๋ ๋ก์ง ๋ถ์๊ธฐ(Logic Analyzer)๋ฅผ ํ์ฉํ์ฌ ์ ๋ฐ ์ธก์ ์ ์งํํด์ผ ํฉ๋๋ค.
- ์ธก์ ๋ฐฉ๋ฒ: LAN9252์
SYNC0ํ์ ์ฑ๋ 1์, STM32์์ SOES ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋ ์งํ ํ ๊ธ(Toggle)๋๋ ํ ์คํธ GPIO ํ์ ์ฑ๋ 2์ ์ฐ๊ฒฐํฉ๋๋ค. - ์ต์ ํ ์ : SPI ์ฐจ๋จํ ํต์ ์ฌ์ฉ ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ง์ฐ ์๊ฐ์ด 45ยตs~120ยตs๋ก ๋ถ๊ท์นํ๊ฒ ๋ณ๋ํ๋ฉฐ **์งํฐ ํญ(Jitter Width)์ด ์ฝ 75ยตs**์ ๋ฌํจ.
- ์ต์ ํ ํ (SPI DMA ์ด์ค ๋ฒํผ ์ ์ฉ): ์ง์ฐ ์๊ฐ์ด 12.5ยตs๋ก ๊ณ ์ ๋๋ฉฐ, **์งํฐ ํญ์ด 0.8ยตs (800ns) ์ดํ**๋ก ๊ธ๊ฒฉํ ๊ฐ์ํจ.
| ๊ตฌ๋ถ (Metric) | ๊ธฐ๋ณธ SPI Blocking ๋ฐฉ์ | SPI DMA + ์ด์ค ๋ฒํผ ์ต์ ํ |
|---|---|---|
| ํ๊ท ์ฒ๋ฆฌ ์ง์ฐ (Latency) | 68.5 ยตs | 12.2 ยตs |
| ์ต๋ ์งํฐ (Max Jitter) | ยฑ37.5 ยตs | ยฑ0.4 ยตs |
| CPU ์ ์ ์จ (CPU Load) | ์ฝ 42% (250ยตs ์ฃผ๊ธฐ ๊ธฐ์ค) | ์ฝ 6% |
5. ๊ฒฐ๋ก ๋ฐ ์์ฝ
STM32์ LAN9252๋ฅผ ๊ฒฐํฉํ์ฌ ๊ณ ์ EtherCAT ์ฌ๋ ์ด๋ธ ๋ ธ๋๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ๊ตฌ์ถํ๋ ค๋ฉด, ๋จ์ํ ์ฝ๋ ํฌํ ์ ๋์ด **ํ๋์จ์ด ์ธํฐํ์ด์ค(SPI Bus)**์ **๋ฉ๋ชจ๋ฆฌ ์ํคํ ์ฒ(DMA & Cache)**์ ๋ํ ์ ๋ฐํ ์ต์ ํ๊ฐ ํ์์ ์ ๋๋ค.
ํต์ฌ ์์ฝ:
- LAN9252์
SYNC0์ธํฐ๋ฝํธ ์งํฐ๋ฅผ ์ต์ํํ๊ธฐ ์ํด NVIC ์ต๊ณ ์ฐ์ ์์๋ฅผ ๋ถ์ฌํ์ธ์. - SOES ์คํ ์คํ ์ค ๋ฐ์ํ๋ CPU ๋ณ๋ชฉ์ ์ ๊ฑฐํ๊ธฐ ์ํด **SPI DMA ๊ธฐ๋ฐ์ ์ด์ค ๋ฒํผ๋ง(Ping-Pong)** ๊ตฌ์กฐ๋ก ๋๋ผ์ด๋ฒ๋ฅผ ์ฌ์ค๊ณํ์ธ์.
- Cortex-M7 ๊ณ์ด MCU๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ **D-Cache ์ผ๊ด์ฑ ๋ฌธ์ **๋ก ์ธํ ํ๋ก์ธ์ค ๋ฐ์ดํฐ ์ค์ผ์ ๋ฐฉ์งํ๊ธฐ ์ํด MPU ์ค์ ์ ๋ฐ๋์ ํ์ธํ์ธ์.
์ด๋ฌํ ํธ๋ฌ๋ธ์ํ ๊ณผ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ์ ์ ์ฉํ๋ฉด 250ยตs ์ดํ์ ์ด๊ณ ์ ๋ฐ์ดํฐ ์ฃผ๊ธฐ์์๋ ์งํฐ ์๋ ๋งค์ฐ ์์ ์ ์ธ ํ๋์จ์ด ์ค์๊ฐ ํต์ ์์คํ ์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.