#include "owi.h" #include "delay.h" #include "r_cg_wdt.h" #include #include #include "uart.h" #include "r_cg_wdt.h" #ifndef OWI_STRONG_DRIVE_HIGH_US #define OWI_STRONG_DRIVE_HIGH_US 5u #endif /* * Test 3 hardware time base * ------------------------- * Project clock: fCLK = 32 MHz * TAU0 channel 5: CK03 = fCLK / 32 = 1 MHz (one count per microsecond) * * Channel 5 and CK03 are otherwise unused by this project. Only the CK03 * field of TPS0 is changed, so CK00 to CK02 remain untouched. */ #define OWI_TIMER_CHANNEL_MASK 0x0020u #define OWI_TIMER_CK03_DIV32 0x5000u #define OWI_TIMER_TMR_CK03_INTERVAL 0xC000u /* 내부 상태 */ static uint32_t bit_period_us = OWI_BIT_PERIOD_US; static uint8_t g_owi_timeout_latched = 0; static uint16_t g_owi_last_timeout_byte_index = 0xFFFFu; static uint8_t g_owi_last_timeout_bit_index = 0xFFu; static uint16_t g_owi_current_read_byte_index = 0u; static uint8_t g_owi_current_read_bit_index = 0u; static uint16_t g_owi_next_bit_start_tick = 0u; static void OWI_TimerStart1MHz(void) { TAU0EN = 1U; NOP(); NOP(); NOP(); NOP(); TT0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; TMMK05 = 1U; TMIF05 = 0U; TOE0 &= (uint16_t)~OWI_TIMER_CHANNEL_MASK; TPS0 = (uint16_t)((TPS0 & 0x0FFFu) | OWI_TIMER_CK03_DIV32); TMR05 = OWI_TIMER_TMR_CK03_INTERVAL; TDR05 = 0xFFFFu; TS0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; } static void OWI_TimerStop(void) { TT0 |= (uint16_t)OWI_TIMER_CHANNEL_MASK; TMIF05 = 0U; } static uint16_t OWI_TimerNow(void) { return (uint16_t)(0xFFFFu - TCR05); } static uint8_t OWI_TimerDeadlineReached(uint16_t deadline) { return ((int16_t)(uint16_t)(OWI_TimerNow() - deadline) >= 0) ? 1u : 0u; } static void OWI_TimerWaitUntil(uint16_t deadline) { while (!OWI_TimerDeadlineReached(deadline)) { NOP(); } } static void OWI_LatchReadTimeout(uint16_t byte_index, uint8_t bit_index) { if (!g_owi_timeout_latched) { g_owi_timeout_latched = 1u; g_owi_last_timeout_byte_index = byte_index; g_owi_last_timeout_bit_index = bit_index; } } static uint8_t OWI_MeasureFallingEdge(uint16_t bit_start, uint16_t byte_index, uint8_t bit_index, uint16_t *edge_tick) { uint16_t bit_end = (uint16_t)(bit_start + (uint16_t)bit_period_us); uint16_t edge; OWI_TimerWaitUntil(bit_start); /* * Each OWI bit starts HIGH. First discard a possible LOW remainder at * the exact boundary, then capture the next HIGH-to-LOW transition. */ while (!GPIO_Read()) { if (OWI_TimerDeadlineReached(bit_end)) { OWI_LatchReadTimeout(byte_index, bit_index); return 0u; } } while (GPIO_Read()) { if (OWI_TimerDeadlineReached(bit_end)) { OWI_LatchReadTimeout(byte_index, bit_index); return 0u; } } edge = OWI_TimerNow(); if ((uint16_t)(edge - bit_start) >= (uint16_t)bit_period_us) { OWI_LatchReadTimeout(byte_index, bit_index); return 0u; } *edge_tick = edge; return 1u; } /* ========================================================= * GPIO helpers (P70 / HW Open-Drain) * - LOW : 출력 모드 + 0 * - HIGH : 입력(Hi-Z)로 release * ========================================================= */ void GPIO_Clear(void) { OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; } void GPIO_Input(void) { OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; } int GPIO_Read(void) { return (OWI_PORT_P & (uint8_t)OWI_PIN_MASK) ? 1 : 0; } static void OWI_Release(void) { OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; } static void GPIO_StrongDriveHighKick(uint32_t kick_us) { OWI_Release(); if (!GPIO_Read()) { return; } OWI_PORT_POM &= (uint8_t)~OWI_PIN_MASK; OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; delay_us(kick_us); OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; OWI_Release(); } void GPIO_ForceHighKick(void) { GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US); } static void OWI_DriveLow(void) { OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; } /* ========================================================= * Diagnostics * ========================================================= */ uint8_t OWI_HasTimeout(void) { return g_owi_timeout_latched; } void OWI_ClearTimeout(void) { g_owi_timeout_latched = 0; g_owi_last_timeout_byte_index = 0xFFFFu; g_owi_last_timeout_bit_index = 0xFFu; } uint16_t OWI_GetLastTimeoutByteIndex(void) { return g_owi_last_timeout_byte_index; } uint8_t OWI_GetLastTimeoutBitIndex(void) { return g_owi_last_timeout_bit_index; } /* ========================================================= * OWI Init * ========================================================= */ void OWI_Init(uint32_t bit_time_us) { bit_period_us = bit_time_us; (void)bit_period_us; OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; OWI_PORT_PU &= (uint8_t)~OWI_PIN_MASK; OWI_ClearTimeout(); GPIO_Input(); } /* ========================================================= * Start/Stop/Secure * ========================================================= */ void OWI_Start(void) { GPIO_Clear(); delay_us(TSTART_HOLD); GPIO_Input(); delay_us(TBIT); } void OWI_Stop(void) { GPIO_Input(); delay_us(TSTOP_LOW); delay_us(TIDLE); } static void OWI_StopWrite(void) { OWI_Release(); delay_us(TSTOP_LOW); delay_us(TIDLE); } static void OWI_StopRead(void) { OWI_DriveLow(); delay_us(TSTOP_LOW); OWI_Release(); delay_us(TIDLE); } static uint8_t OWI_WaitFirstBitStart(void) { int timeout; timeout = (int)(bit_period_us * 4u); /* 첫 번째 HIGH->LOW 시작을 기다림 */ while (GPIO_Read() && timeout-- > 0) { delay_us(1u); } if (timeout <= 0) { if (!g_owi_timeout_latched) { g_owi_timeout_latched = 1; g_owi_last_timeout_byte_index = 0u; g_owi_last_timeout_bit_index = 0u; } return 0u; } return 1u; } static uint8_t OWI_ReadByte_StreamSynced(uint16_t byte_index) { uint8_t data = 0; int b; for (b = 7; b >= 0; b--) { uint8_t bit_index = (uint8_t)(7 - b); uint8_t bit; uint16_t edge_tick; uint16_t edge_position; g_owi_current_read_byte_index = byte_index; g_owi_current_read_bit_index = bit_index; if (!OWI_MeasureFallingEdge(g_owi_next_bit_start_tick, byte_index, bit_index, &edge_tick)) { break; } edge_position = (uint16_t)(edge_tick - g_owi_next_bit_start_tick); /* * OWI write timing is HIGH first and LOW second: * 0: falling edge near TBIT/4 * 1: falling edge near 3*TBIT/4 */ bit = (edge_position < (uint16_t)(bit_period_us / 2u)) ? 0u : 1u; data |= (uint8_t)(bit << b); g_owi_next_bit_start_tick = (uint16_t)(g_owi_next_bit_start_tick + (uint16_t)bit_period_us); } return data; } void OWI_SecureStop(void) { int i; GPIO_Clear(); delay_us(SECURE_HIGH); for (i = 0; i < (int)SECURE_TOGGLE_COUNT; i++) { GPIO_Input(); delay_us(SECURE_TOGGLE_HIGH); GPIO_Clear(); delay_us(SECURE_TOGGLE_LOW); } GPIO_Input(); delay_us(SECURE_HIGH); GPIO_Clear(); delay_us(TSTART_HOLD); GPIO_Input(); } /* ========================================================= * Bit/Byte IO * ========================================================= */ void OWI_WriteBit(int bit) { uint32_t t_low = bit ? (uint32_t)TLOW_1 : (uint32_t)TLOW_0; uint32_t t_high = (uint32_t)TBIT - t_low; /* HIGH 구간 */ OWI_Release(); delay_us(t_high); /* LOW 구간 */ OWI_DriveLow(); delay_us(t_low); /* 다음 슬롯 시작 전 반드시 release */ OWI_Release(); } void OWI_WriteByte(uint8_t data) { int i; for (i = 7; i >= 0; i--) { OWI_WriteBit((data >> i) & 0x01u); } GPIO_Input(); } uint8_t OWI_ReadBit(void) { int timeout; int low_width = 0; /* 1) 라인이 HIGH가 될 때까지 정리 */ timeout = (int)(bit_period_us * 2u); while (!GPIO_Read() && timeout-- > 0) { delay_us(1u); } if (timeout <= 0) { if (!g_owi_timeout_latched) { g_owi_timeout_latched = 1; g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; } return 0u; } /* 2) 다음 LOW 시작 대기 */ timeout = (int)(bit_period_us * 2u); while (GPIO_Read() && timeout-- > 0) { delay_us(1u); } if (timeout <= 0) { if (!g_owi_timeout_latched) { g_owi_timeout_latched = 1; g_owi_last_timeout_byte_index = g_owi_current_read_byte_index; g_owi_last_timeout_bit_index = g_owi_current_read_bit_index; } return 0u; } /* 3) LOW가 유지되는 시간을 직접 측정 */ while (!GPIO_Read() && low_width < (int)(bit_period_us * 2u)) { delay_us(1u); low_width++; } /* 4) LOW 폭 기준으로 판정 - 짧으면 1 - 길면 0 threshold ~= TBIT/2 */ return (low_width < (int)(bit_period_us / 2u)) ? 1u : 0u; } uint8_t OWI_ReadByte(void) { uint8_t data = 0; int i; for (i = 7; i >= 0; i--) { g_owi_current_read_bit_index = (uint8_t)(7 - i); data |= (uint8_t)(OWI_ReadBit() << i); if (OWI_HasTimeout()) { break; } } return data; } /* ========================================================= * Debug Print * ========================================================= */ void OWI_T_ReadBytesAndPrint(int length) { uint8_t buf[129]; int i; char uart_buf[8]; char tmp_buf[8]; uint8_t va0, va1; if (length > 129) length = 129; if (length <= 0) return; OWI_ClearTimeout(); for (i = 0; i < length; i++) { R_WDT_Restart(); g_owi_current_read_byte_index = (uint16_t)i; buf[i] = OWI_ReadByte(); if (OWI_HasTimeout()) { i++; break; } } sprintf(uart_buf, "%02X ", buf[0]); strcpy(tmp_buf, uart_buf); HOST_PRINT(tmp_buf); for (i = 1; i < length; i += 2) { va0 = buf[i]; va1 = (uint8_t)((i + 1 < length) ? buf[i + 1] : 0u); delay_us(200); sprintf(uart_buf, "%02X%02X ", va0, va1); strcpy(tmp_buf, uart_buf); HOST_PRINT(tmp_buf); delay_us(200); } } /* ========================================================= * Raw helpers * ========================================================= */ static void owi_result_init(owi_io_result_t *r) { if (!r) return; memset(r, 0, sizeof(*r)); r->ok = 1; r->timeout_byte_index = 0xFFFFu; r->timeout_bit_index = 0xFFu; } static void owi_result_latch_timeout(owi_io_result_t *r) { if (!r) return; if (OWI_HasTimeout()) { r->ok = 0; r->timeout = 1; r->timeout_byte_index = OWI_GetLastTimeoutByteIndex(); r->timeout_bit_index = OWI_GetLastTimeoutBitIndex(); } } void OWI_T_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) { int i; owi_result_init(r); //delay_us(200); OWI_Init(OWI_BIT_PERIOD_US); OWI_ClearTimeout(); R_WDT_Restart(); OWI_SecureStop(); R_WDT_Restart(); OWI_WriteByte((uint8_t)(id << 1)); R_WDT_Restart(); for (i = 0; i < (int)tx_len; i++) { R_WDT_Restart(); OWI_WriteByte(tx_data[i]); R_WDT_Restart(); } OWI_Stop(); R_WDT_Restart(); owi_result_latch_timeout(r); } void OWI_CommandModeRaw(const uint8_t *tx_data, uint8_t tx_len, uint8_t id, owi_io_result_t *r) { int i; owi_result_init(r); OWI_Init(OWI_BIT_PERIOD_US); OWI_ClearTimeout(); R_WDT_Restart(); OWI_SecureStop(); R_WDT_Restart(); OWI_WriteByte((uint8_t)(id << 1)); R_WDT_Restart(); for (i = 0; i < (int)tx_len; i++) { R_WDT_Restart(); OWI_WriteByte(tx_data[i]); R_WDT_Restart(); } OWI_Stop(); R_WDT_Restart(); owi_result_latch_timeout(r); } void OWI_ReadBytesRaw(int length, uint8_t id, owi_io_result_t *r) { int i; int max_len; if (!r) return; owi_result_init(r); OWI_Init(OWI_BIT_PERIOD_US); if (length <= 0) { r->ok = 0; return; } max_len = (int)OWI_IO_MAX_BYTES; if (length > max_len) { length = max_len; } r->read_len = (uint16_t)length; OWI_ClearTimeout(); R_WDT_Restart(); OWI_SecureStop(); OWI_TimerStart1MHz(); OWI_WriteByte((uint8_t)((id << 1) | 1u)); /* * OWI_WriteByte() returns at the end of the R bit. Each bit slot and its * falling-edge position are measured from this absolute reference. */ g_owi_next_bit_start_tick = OWI_TimerNow(); for (i = 0; i < length; i++) { R_WDT_Restart(); r->data[i] = OWI_ReadByte_StreamSynced((uint16_t)i); if (OWI_HasTimeout()) { owi_result_latch_timeout(r); break; } } OWI_TimerStop(); OWI_StopRead(); } void OWI_disable(void) { HOST_PRINT("51\r\n"); } void OWI_T_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) { owi_io_result_t r; (void)r; OWI_T_CommandModeRaw(tx_data, tx_len, id, &r); HOST_PRINT("51\r\n"); } void OWI_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) { owi_io_result_t r; (void)r; OWI_CommandModeRaw(tx_data, tx_len, id, &r); HOST_PRINT("51\r\n"); } void OWI_ReadBytesAndPrint(int length, uint8_t id) { owi_io_result_t r; char out[(2 * OWI_IO_MAX_BYTES) + 40]; int i; uint16_t p = 0; if (length <= 0) { HOST_PRINT("Err:read_len_nonzero\r\n"); return; } OWI_ReadBytesRaw(length, id, &r); if (r.read_len == 0) { HOST_PRINT("Err:read_len_nonzero\r\n"); return; } for (i = 0; i < (int)r.read_len; i++) { uint8_t b = r.data[i]; out[p++] = "0123456789ABCDEF"[b >> 4]; out[p++] = "0123456789ABCDEF"[b & 0x0F]; } if (r.timeout) { p += (uint16_t)sprintf(&out[p], " !TO(B%u b%u)", (unsigned)r.timeout_byte_index, (unsigned)r.timeout_bit_index); } out[p++] = '\r'; out[p++] = '\n'; out[p] = '\0'; HOST_PRINT(out); }