#include "owi.h" #include "delay.h" #include #include #include "uart.h" #ifndef OWI_STRONG_DRIVE_HIGH_US #define OWI_STRONG_DRIVE_HIGH_US 5u /* 5~20us 정도로 시작해서 튜닝 */ #endif /* 내부 상태 */ static uint32_t bit_period_us = OWI_BIT_PERIOD_US; static uint8_t g_owi_timeout_latched = 0; /* ========================================================= * GPIO helpers (P70 / HW Open-Drain) * - LOW : 출력 모드 + 0 * - HIGH : 입력(Hi-Z)로 release (pull-up으로 상승) * ========================================================= */ void GPIO_Clear(void) { /* open-drain ON 보장 */ OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; /* latch low */ OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; /* output */ OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; } void GPIO_Input(void) { OWI_PORT_POM |= OWI_PIN_MASK; // ★ 반드시 OWI_PORT_P |= OWI_PIN_MASK; // latch HIGH OWI_PORT_PM |= OWI_PIN_MASK; } int GPIO_Read(void) { return (OWI_PORT_P & (uint8_t)OWI_PIN_MASK) ? 1 : 0; } void OWI_Release(void) { /* open-drain ON */ OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; /* latch high (release 상태에서 깔끔) */ OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; /* input = Hi-Z */ OWI_PORT_PM |= (uint8_t)OWI_PIN_MASK; } static void GPIO_StrongDriveHighKick(uint32_t kick_us) { /* 1) 우선 release 상태로 */ OWI_Release(); /* 2) 라인이 LOW면(누가 당기면) 강제 HIGH 금지 */ if (!GPIO_Read()) { return; } /* 3) 오픈드레인 OFF -> push-pull */ OWI_PORT_POM &= (uint8_t)~OWI_PIN_MASK; /* 4) 출력 HIGH로 강하게 밀어올림 */ OWI_PORT_P |= (uint8_t)OWI_PIN_MASK; /* latch high */ OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; /* output */ delay_us(kick_us); /* 5) 다시 오픈드레인 ON + release(Hi-Z) */ OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; OWI_Release(); } void GPIO_ForceHighKick(void) { GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US); } void OWI_DriveLow(void) { /* open-drain ON */ OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; /* latch low */ OWI_PORT_P &= (uint8_t)~OWI_PIN_MASK; /* output */ OWI_PORT_PM &= (uint8_t)~OWI_PIN_MASK; } /* ========================================================= * OWI Init * ========================================================= */ void OWI_Init(uint32_t bit_time_us) { bit_period_us = bit_time_us; (void)bit_period_us; /* 현재 타이밍은 매크로(TBIT) 사용 */ /* HW Open-Drain enable: P70만 */ OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK; /* 내부 Pull-up: 필요 시 사용(외부 풀업이면 꺼도 됨) */ //OWI_PORT_PU |= (uint8_t)OWI_PIN_MASK; OWI_PORT_PU &= (uint8_t)~OWI_PIN_MASK; // P70만 OFF /* idle = release */ GPIO_Input(); } /* ========================================================= * Start/Stop/Secure * ========================================================= */ void OWI_Start(void) { GPIO_Clear(); delay_us(TSTART_HOLD); GPIO_Input(); GPIO_StrongDriveHighKick(OWI_STRONG_DRIVE_HIGH_US); delay_us(TBIT); } void OWI_Stop(void) { GPIO_Input(); delay_us(TSTOP_LOW); delay_us(TIDLE); //GPIO_Clear(); } /* ========================================================= * Stop conditions * - Write stop : keep line HIGH (release) for tOWI_STOP * - Read stop : clamp line LOW for tOWI_STOP to terminate slave response loop * ========================================================= */ static void OWI_StopWrite(void) { /* Request 종료: HIGH 고정(Release) */ OWI_Release(); delay_us(TSTOP_LOW); /* tOWI_STOP (>= 2*TBIT 권장) */ delay_us(TIDLE); /* bus free time */ } static void OWI_StopRead(void) { /* Response 종료: 마스터가 LOW로 클램프해서 stop 생성 */ OWI_DriveLow(); delay_us(TSTOP_LOW); /* tOWI_STOP */ OWI_Release(); delay_us(TIDLE); } void OWI_SecureStop(void) { int i; GPIO_Clear(); delay_us(SECURE_HIGH); for (i = 0; i < (int)SECURE_TOGGLE_COUNT; i++) { /* HIGH 구간: release + strong kick */ GPIO_Input(); delay_us(SECURE_TOGGLE_HIGH); //GPIO_ForceHighKick(); // if (SECURE_TOGGLE_HIGH > OWI_STRONG_HIGH_US) { // delay_us(SECURE_TOGGLE_HIGH - OWI_STRONG_HIGH_US); // } /* LOW 구간 */ GPIO_Clear(); delay_us(SECURE_TOGGLE_LOW); } /* 마지막 HIGH */ GPIO_Input(); GPIO_ForceHighKick(); if (SECURE_HIGH > OWI_STRONG_HIGH_US) { delay_us(SECURE_HIGH - OWI_STRONG_HIGH_US); } /* 이어서 기존 시퀀스 유지 */ 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(); /* (선택) HIGH 초반에만 아주 짧게 킥 */ GPIO_StrongDriveHighKick(5u); /* 나머지 HIGH 시간 */ if (t_high > 5u) delay_us(t_high - 5u); /* LOW 구간 */ OWI_DriveLow(); delay_us(t_low); } 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) { uint8_t bit; int timeout = (int)(bit_period_us * 2u); while (!(GPIO_Read()) && timeout-- > 0) { delay_us(1); } if (timeout <= 0) { if (!g_owi_timeout_latched) { HOST_PRINT("OWI Timeout\r\n"); g_owi_timeout_latched = 1; } return 0xFF; } delay_us((bit_period_us * 1u) / 2u); bit = (uint8_t)GPIO_Read(); delay_us((bit_period_us * 2u) / 5u); return bit; } uint8_t OWI_ReadByte(void) { uint8_t data = 0; int i; for (i = 7; i >= 0; i--) { data |= (uint8_t)(OWI_ReadBit() << i); } 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; for (i = 0; i < length; i++) { buf[i] = OWI_ReadByte(); } 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 = buf[i + 1]; delay(10000); sprintf(uart_buf, "%02X%02X ", va0, va1); strcpy(tmp_buf, uart_buf); HOST_PRINT(tmp_buf); delay(10000); } } /* ========================================================= * Command / Diagnostic (네 로직 유지) * ========================================================= */ #define OWI_MAX_RETRY 2 #define OWI_RECOVERY_MIN_US 500 void OWI_A_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) { uint8_t CMD_LIST[6][4] = { {0x50,0x2E,0x00,0x00}, {0x50,0x2E,0x01,0x00}, {0x50,0x2E,0x02,0x00}, {0x50,0x2E,0x16,0x00}, {0x50,0x2E,0x41,0x00}, {0x50,0x2E,0x00,0x00} }; char line[128]; size_t n = 0; uint8_t rx[RAM_BYTES]; int i, j, retry, all_ff; uint8_t read_address = 0x51; delay_us(7000); for (j = 0; j < 6; j++) { OWI_SecureStop(); for (i = 0; i < 4; i++) { OWI_WriteByte(CMD_LIST[j][i]); } OWI_Stop(); delay_us(OWI_RECOVERY_MIN_US); for (i = 0; i < RAM_BYTES; i++) rx[i] = 0xFF; for (retry = 0; retry <= OWI_MAX_RETRY; retry++) { delay_us(OWI_RECOVERY_MIN_US); OWI_SecureStop(); OWI_WriteByte(read_address); for (i = 0; i < RAM_BYTES; i++) rx[i] = OWI_ReadByte(); OWI_Stop(); all_ff = 1; for (i = 0; i < RAM_BYTES; i++) { if (rx[i] != 0xFF) { all_ff = 0; break; } } if (!all_ff) break; if (retry == OWI_MAX_RETRY) { return; } } n += sprintf(&line[n], "%02X%02X", rx[1], rx[2]); line[n++] = ','; } if (tx_data != NULL && tx_len == 3) { for (retry = 0; retry <= OWI_MAX_RETRY; retry++) { OWI_SecureStop(); OWI_WriteByte((uint8_t)(id << 1)); for (i = 0; i < 3; i++) { OWI_WriteByte(tx_data[i]); } OWI_Stop(); delay_us(OWI_RECOVERY_MIN_US); for (i = 0; i < RAM_BYTES; i++) rx[i] = 0xFF; OWI_SecureStop(); OWI_WriteByte((uint8_t)((id << 1) | 1u)); for (i = 0; i < RAM_BYTES; i++) { rx[i] = OWI_ReadByte(); } OWI_Stop(); all_ff = 1; for (i = 0; i < RAM_BYTES; i++) { if (rx[i] != 0xFF) { all_ff = 0; break; } } if (!all_ff) break; if (retry == OWI_MAX_RETRY) { return; } } n += sprintf(&line[n], "%02X%02X", rx[1], rx[2]); } else { n += sprintf(&line[n], "0000"); } line[n++] = '\r'; line[n++] = '\n'; line[n] = '\0'; HOST_PRINT(line); delay(10000); } 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) { int i; delay_us(10000); OWI_Init(OWI_BIT_PERIOD_US); OWI_SecureStop(); OWI_WriteByte((uint8_t)(id << 1)); for (i = 0; i < (int)tx_len; i++) { OWI_WriteByte(tx_data[i]); } OWI_Stop(); HOST_PRINT("51\r\n"); } void OWI_CommandMode(const uint8_t *tx_data, uint8_t tx_len, uint8_t id) { int i; OWI_SecureStop(); OWI_WriteByte((uint8_t)(id << 1)); for (i = 0; i < (int)tx_len; i++) { OWI_WriteByte(tx_data[i]); } OWI_Stop(); HOST_PRINT("51\r\n"); } void OWI_ReadBytesAndPrint(int length, uint8_t id) { static uint8_t buf[600]; static char out[2*600 + 3]; int i; uint16_t p = 0; if (length <= 0) { HOST_PRINT("Err:read_len_nonzero\r\n"); return; } if (length > 600) length = 600; g_owi_timeout_latched = 0; OWI_SecureStop(); OWI_WriteByte((uint8_t)((id << 1) | 1u)); for (i = 0; i < length; i++) { buf[i] = OWI_ReadByte(); } for (i = 0; i < length; i++) { uint8_t b = buf[i]; out[p++] = "0123456789ABCDEF"[b >> 4]; out[p++] = "0123456789ABCDEF"[b & 0x0F]; } out[p++] = '\r'; out[p++] = '\n'; out[p] = '\0'; OWI_StopRead(); HOST_PRINT(out); }