17 changed files with 4238 additions and 2218 deletions
@ -0,0 +1,596 @@ |
|||
#include "owi.h" |
|||
/*
|
|||
* Test 1: bit-period-only variant. |
|||
* This local override keeps the replacement self-contained in owi.c. |
|||
* TBIT and all timing macros in owi.h expand from this value at use time. |
|||
*/ |
|||
#undef OWI_BIT_PERIOD_US |
|||
#define OWI_BIT_PERIOD_US 2000u |
|||
|
|||
#include "delay.h" |
|||
#include "r_cg_wdt.h" |
|||
#include <string.h> |
|||
#include <stdio.h> |
|||
#include "uart.h" |
|||
#include "r_cg_wdt.h" |
|||
|
|||
#ifndef OWI_STRONG_DRIVE_HIGH_US |
|||
#define OWI_STRONG_DRIVE_HIGH_US 5u |
|||
#endif |
|||
|
|||
/* 내부 상태 */ |
|||
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; |
|||
|
|||
/* =========================================================
|
|||
* 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_WaitForFallingEdge(uint16_t byte_index, uint8_t bit_index) |
|||
{ |
|||
int timeout = (int)(bit_period_us * 4u); |
|||
|
|||
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 = byte_index; |
|||
g_owi_last_timeout_bit_index = bit_index; |
|||
} |
|||
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; |
|||
|
|||
g_owi_current_read_byte_index = byte_index; |
|||
g_owi_current_read_bit_index = bit_index; |
|||
|
|||
/* 슬롯 시작 후 중앙 샘플 */ |
|||
delay_us(bit_period_us / 2u); |
|||
bit = GPIO_Read() ? 1u : 0u; |
|||
data |= (uint8_t)(bit << b); |
|||
|
|||
/* 남은 반 슬롯 대기 */ |
|||
delay_us(bit_period_us / 2u); |
|||
} |
|||
|
|||
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; |
|||
uint8_t is_long_read; |
|||
|
|||
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(); |
|||
|
|||
/* Only 119 keeps the established mid-stream sync. */ |
|||
is_long_read = (length == 119) ? 1u : 0u; |
|||
|
|||
R_WDT_Restart(); |
|||
OWI_SecureStop(); |
|||
OWI_WriteByte((uint8_t)((id << 1) | 1u)); |
|||
|
|||
/*
|
|||
* For 129 bytes, wait for the first edge immediately after the read ID. |
|||
* The old 100us delay could enter an already-started first pulse. |
|||
* Preserve the established delay for every other read length. |
|||
*/ |
|||
if (length != 129) { |
|||
delay_us(100u); |
|||
} |
|||
|
|||
R_WDT_Restart(); |
|||
if (!OWI_WaitForFallingEdge(0u, 0u)) { |
|||
owi_result_latch_timeout(r); |
|||
OWI_StopRead(); |
|||
return; |
|||
} |
|||
|
|||
for (i = 0; i < length; i++) { |
|||
R_WDT_Restart(); |
|||
|
|||
/* Preserve the existing mid-stream sync for the 119-byte path only. */ |
|||
if (is_long_read && i == (length - 50)) { |
|||
R_WDT_Restart(); |
|||
if (!OWI_WaitForFallingEdge((uint16_t)i, 0u)) { |
|||
owi_result_latch_timeout(r); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
r->data[i] = OWI_ReadByte_StreamSynced((uint16_t)i); |
|||
|
|||
if (OWI_HasTimeout()) { |
|||
owi_result_latch_timeout(r); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
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); |
|||
} |
|||
@ -0,0 +1,602 @@ |
|||
#include "owi.h" |
|||
#include "delay.h" |
|||
#include "r_cg_wdt.h" |
|||
#include <string.h> |
|||
#include <stdio.h> |
|||
#include "uart.h" |
|||
#include "r_cg_wdt.h" |
|||
|
|||
#ifndef OWI_STRONG_DRIVE_HIGH_US |
|||
#define OWI_STRONG_DRIVE_HIGH_US 5u |
|||
#endif |
|||
|
|||
/*
|
|||
* Test 2 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_sample_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 void OWI_TimerWaitUntil(uint16_t deadline) |
|||
{ |
|||
while ((int16_t)(uint16_t)(OWI_TimerNow() - deadline) < 0) { |
|||
NOP(); |
|||
} |
|||
} |
|||
|
|||
/* =========================================================
|
|||
* 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; |
|||
|
|||
g_owi_current_read_byte_index = byte_index; |
|||
g_owi_current_read_bit_index = bit_index; |
|||
|
|||
/*
|
|||
* The deadline is advanced from the R-bit end reference, never from |
|||
* the end of the previous CPU delay. Per-byte processing time |
|||
* therefore cannot accumulate as sampling drift. |
|||
*/ |
|||
OWI_TimerWaitUntil(g_owi_next_sample_tick); |
|||
bit = GPIO_Read() ? 1u : 0u; |
|||
data |= (uint8_t)(bit << b); |
|||
g_owi_next_sample_tick = |
|||
(uint16_t)(g_owi_next_sample_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. Every sample deadline |
|||
* is an absolute 1 MHz timer value derived from this one reference. |
|||
*/ |
|||
g_owi_next_sample_tick = |
|||
(uint16_t)(OWI_TimerNow() + (uint16_t)(bit_period_us / 2u)); |
|||
|
|||
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); |
|||
} |
|||
@ -0,0 +1,666 @@ |
|||
#include "owi.h" |
|||
#include "delay.h" |
|||
#include "r_cg_wdt.h" |
|||
#include <string.h> |
|||
#include <stdio.h> |
|||
#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); |
|||
} |
|||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
File diff suppressed because it is too large
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue