You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

749 lines
19 KiB

#include "owi.h"
#include "r_cg_wdt.h"
#include "delay.h"
#include "r_cg_timer.h"
#include "r_cg_cgc.h"
#include <string.h>
/* 내부 상태 */
#ifndef OWI_USE_TAU1_CAPTURE
#define OWI_USE_TAU1_CAPTURE 1u
#endif
/* Renesas CG: count-clock period is half the selected 0.063 us minimum.
Therefore TI15 capture runs at approximately 32 timer ticks per us. */
#define OWI_TAU1_TICKS_PER_US 32UL
#define OWI_CAPTURE_QUEUE_WAIT_US (bit_period_us * 4u)
#define OWI_CAPTURE_SYNC_BITS 16u
/* 내부 상태 */
static uint32_t bit_period_us = OWI_BIT_PERIOD_US;
static uint8_t g_owi_timeout_latched = 0;
/* 0=none, 1=no pulse, 2=queue overflow, 3=header mismatch. */
static uint8_t g_capture_error = 0U;
static uint16_t g_capture_sync = 0U;
uint8_t OWI_GetCaptureError(void) { return g_capture_error; }
uint16_t OWI_GetCaptureSync(void) { return g_capture_sync; }
#if OWI_USE_TAU1_CAPTURE
static uint32_t g_owi_capture_threshold_ticks = 0UL;
static uint8_t g_owi_capture_pending_bits[OWI_CAPTURE_SYNC_BITS];
static uint8_t g_owi_capture_pending_index = 0U;
static uint8_t g_owi_capture_pending_count = 0U;
#endif
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 void OWI_KickWdt(void)
{
R_WDT_Restart();
NVM_TraceStack();
}
/* =========================================================
* 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 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_capture_error = 0U;
g_capture_sync = 0U;
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;
PMC7 &= (uint8_t)~OWI_PIN_MASK;
PIM7 &= (uint8_t)~OWI_PIN_MASK;
OWI_PORT_POM |= (uint8_t)OWI_PIN_MASK;
OWI_PORT_PU &= (uint8_t)~OWI_PIN_MASK;
OWI_ClearTimeout();
GPIO_Input();
OWI_KickWdt();
}
/* =========================================================
* 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_StopRead(void)
{
OWI_DriveLow();
delay_us(TSTOP_LOW);
OWI_Release();
delay_us(TIDLE);
}
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;
}
#if OWI_USE_TAU1_CAPTURE
static void OWI_CapturePrepare(void)
{
/* P70 remains a normal open-drain GPIO at boot. Configure TI15 only
immediately before a captured receive transaction. */
/* R_Systeminit configured TAU1; do not reset unrelated channels. */
R_TAU1_Channel5_Stop();
/* Slow RC rising edges on P70 benefit from the TI15 digital noise filter.
Give capture precedence over UART interrupts while receiving a frame. */
NFEN2 |= _20_TAU_CH5_NOISE_ON;
TMPR115 = 0U;
TMPR015 = 0U;
GPIO_Input();
}
static void OWI_CaptureBegin(void)
{
/* Arm while the master still holds the final address LOW.
Its release is the first edge; the first complete slave LOW follows. */
g_owi_capture_threshold_ticks = 0UL;
g_owi_capture_pending_index = 0U;
g_owi_capture_pending_count = 0U;
R_TAU1_Channel5_CaptureReset();
g_trace_stage = 7U;
R_TAU1_Channel5_Start();
}
/* Send the read address and arm capture BEFORE releasing its final LOW.
Otherwise the GPIO/function-return overhead can lose the first response bit. */
static void OWI_WriteCapturedReadAddress(uint8_t address)
{
int b;
uint32_t t_low = (address & 1U) ? (uint32_t)TLOW_1 : (uint32_t)TLOW_0;
for (b = 7; b > 0; b--) OWI_WriteBit((address >> b) & 1U);
OWI_Release();
delay_us((uint32_t)TBIT - t_low);
OWI_DriveLow();
delay_us(t_low);
OWI_CaptureBegin();
OWI_Release();
}
static void OWI_CaptureEnd(void)
{
R_TAU1_Channel5_Stop();
GPIO_Input();
}
static uint8_t OWI_CaptureWaitLowWidth(uint16_t byte_index,
uint8_t bit_index,
uint32_t * const low_ticks)
{
uint32_t timeout_us = OWI_CAPTURE_QUEUE_WAIT_US;
while (timeout_us-- > 0UL)
{
/* Keep the bounded wait alive even when the input stays idle. */
if ((timeout_us & 63UL) == 0UL) OWI_KickWdt();
if (R_TAU1_Channel5_CaptureOverflowed()) break;
if (R_TAU1_Channel5_GetLowWidthTicks(low_ticks))
{
return 1U;
}
if (R_TAU1_Channel5_CaptureOverflowed())
{
break;
}
/* This delay is only a timeout yield; pulse timing is captured by TAU1. */
delay_us(1U);
}
if (!g_owi_timeout_latched)
{
g_capture_error = R_TAU1_Channel5_CaptureOverflowed() ? 2U : 1U;
g_owi_timeout_latched = 1U;
g_owi_last_timeout_byte_index = byte_index;
g_owi_last_timeout_bit_index = bit_index;
}
return 0U;
}
static uint32_t OWI_CaptureFindThreshold(const uint32_t *widths,
uint8_t width_count)
{
uint32_t sorted[OWI_CAPTURE_SYNC_BITS];
uint32_t max_gap = 0UL;
uint32_t threshold =
((uint32_t)bit_period_us * OWI_TAU1_TICKS_PER_US) / 2UL;
uint32_t gap;
uint32_t temp;
uint8_t i;
uint8_t j;
for (i = 0U; i < width_count; i++) {
sorted[i] = widths[i];
}
for (i = 0U; i < (uint8_t)(width_count - 1U); i++) {
for (j = (uint8_t)(i + 1U); j < width_count; j++) {
if (sorted[j] < sorted[i]) {
temp = sorted[i];
sorted[i] = sorted[j];
sorted[j] = temp;
}
}
}
/* The 0x26 header contains both short and long LOW pulses. The largest
gap separates the two measured clusters without assuming timer scale. */
for (i = 0U; i < (uint8_t)(width_count - 1U); i++) {
gap = sorted[i + 1U] - sorted[i];
if (gap > max_gap) {
max_gap = gap;
threshold = sorted[i] + (gap / 2UL);
}
}
return threshold;
}
static uint8_t OWI_CaptureExpectedHeaderBit(uint8_t header_bit_index)
{
return (uint8_t)((0x26U >> (7U - header_bit_index)) & 0x01U);
}
/* Find a complete header in the bounded startup window. The read-address
release may add a leading capture (observed SYNC=9343: 1|00100110|1000011).
Preserve every bit after the header; never reconstruct a partial header. */
static uint8_t OWI_CaptureFindHeaderEnd(const uint8_t *bits,
uint8_t bit_count,
uint8_t * const header_end)
{
uint8_t start;
uint8_t i;
if (!bits || !header_end || bit_count < 8U ||
bit_count > OWI_CAPTURE_SYNC_BITS) return 0U;
for (start = 0U; start <= (uint8_t)(bit_count - 8U); start++) {
for (i = 0U; i < 8U; i++) {
if (bits[start + i] != OWI_CaptureExpectedHeaderBit(i)) break;
}
if (i == 8U) {
*header_end = (uint8_t)(start + 8U);
return 1U;
}
}
return 0U;
}
static uint8_t OWI_CaptureGetDecodedBit(uint16_t byte_index,
uint8_t bit_index,
uint8_t * const decoded_bit)
{
uint32_t low_ticks;
if (decoded_bit == 0) {
return 0U;
}
if (g_owi_capture_pending_index < g_owi_capture_pending_count) {
*decoded_bit = g_owi_capture_pending_bits[g_owi_capture_pending_index++];
return 1U;
}
if (!OWI_CaptureWaitLowWidth(byte_index, bit_index, &low_ticks)) {
return 0U;
}
*decoded_bit = (low_ticks < g_owi_capture_threshold_ticks) ? 1U : 0U;
return 1U;
}
static uint8_t OWI_ReadByte_Captured(uint16_t byte_index)
{
uint8_t data = 0U;
int b;
uint32_t sync_widths[OWI_CAPTURE_SYNC_BITS];
if (byte_index == 0U)
{
uint8_t sync_bits[OWI_CAPTURE_SYNC_BITS];
uint8_t header_end;
uint8_t i;
for (i = 0U; i < OWI_CAPTURE_SYNC_BITS; i++)
{
OWI_KickWdt();
g_owi_current_read_byte_index = 0U;
g_owi_current_read_bit_index = i;
if (!OWI_CaptureWaitLowWidth(0U, i, &sync_widths[i]))
{
return 0U;
}
}
g_owi_capture_threshold_ticks =
OWI_CaptureFindThreshold(sync_widths, OWI_CAPTURE_SYNC_BITS);
for (i = 0U; i < OWI_CAPTURE_SYNC_BITS; i++) {
sync_bits[i] =
(sync_widths[i] < g_owi_capture_threshold_ticks) ? 1U : 0U;
}
g_capture_sync = 0U;
for (i = 0U; i < OWI_CAPTURE_SYNC_BITS; i++) {
g_capture_sync = (uint16_t)((g_capture_sync << 1) | sync_bits[i]);
}
if (!OWI_CaptureFindHeaderEnd(sync_bits,
OWI_CAPTURE_SYNC_BITS,
&header_end)) {
if (!g_owi_timeout_latched) {
g_owi_timeout_latched = 1U;
g_capture_error = 3U;
g_owi_last_timeout_byte_index = 0U;
g_owi_last_timeout_bit_index = 0U;
}
return 0U;
}
g_owi_capture_pending_index = 0U;
g_owi_capture_pending_count =
(uint8_t)(OWI_CAPTURE_SYNC_BITS - header_end);
for (i = 0U; i < g_owi_capture_pending_count; i++) {
g_owi_capture_pending_bits[i] = sync_bits[header_end + i];
}
return 0x26U;
}
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;
if (!OWI_CaptureGetDecodedBit(byte_index, bit_index, &bit))
{
break;
}
if (bit)
{
data |= (uint8_t)(1U << b);
}
}
return data;
}
#endif
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;
}
/* =========================================================
* 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();
OWI_KickWdt();
OWI_SecureStop();
OWI_KickWdt();
OWI_WriteByte((uint8_t)(id << 1));
OWI_KickWdt();
for (i = 0; i < (int)tx_len; i++) {
OWI_KickWdt();
OWI_WriteByte(tx_data[i]);
OWI_KickWdt();
}
OWI_Stop();
OWI_KickWdt();
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();
OWI_KickWdt();
OWI_SecureStop();
OWI_KickWdt();
OWI_WriteByte((uint8_t)(id << 1));
OWI_KickWdt();
for (i = 0; i < (int)tx_len; i++) {
OWI_KickWdt();
OWI_WriteByte(tx_data[i]);
OWI_KickWdt();
}
OWI_Stop();
OWI_KickWdt();
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 = 0U;
OWI_ClearTimeout();
is_long_read = (length >= 119) ? 1u : 0u;
OWI_KickWdt();
#if OWI_USE_TAU1_CAPTURE
if (length == 127) OWI_CapturePrepare();
#endif
OWI_SecureStop();
#if OWI_USE_TAU1_CAPTURE
if (length == 127) OWI_WriteCapturedReadAddress((uint8_t)((id << 1) | 1u));
else
#endif
OWI_WriteByte((uint8_t)((id << 1) | 1u));
/* 기존 잘 되던 값 유지 */
#if OWI_USE_TAU1_CAPTURE
if (length == 127) {
for (i = 0; i < length; i++) {
uint8_t value;
OWI_KickWdt();
g_trace_stage = 8U;
g_trace_byte = (uint16_t)i;
value = OWI_ReadByte_Captured((uint16_t)i);
if (R_TAU1_Channel5_CaptureOverflowed() && !OWI_HasTimeout()) {
g_owi_timeout_latched = 1U;
g_owi_last_timeout_byte_index = (uint16_t)i;
g_owi_last_timeout_bit_index = 0xFFU;
g_capture_error = 2U;
}
if (OWI_HasTimeout()) {
owi_result_latch_timeout(r);
break;
}
r->data[r->read_len++] = value;
}
g_trace_stage = 9U;
OWI_CaptureEnd();
OWI_StopRead();
OWI_KickWdt();
return;
}
#endif
delay_us(100u);
OWI_KickWdt();
/* 첫 falling edge를 한 번 잡는다 */
if (!OWI_WaitForFallingEdge(0u, 0u)) {
owi_result_latch_timeout(r);
OWI_StopRead();
OWI_KickWdt();
return;
}
for (i = 0; i < length; i++) {
OWI_KickWdt();
/* long read만 주기적 재동기화 */
if (is_long_read && i == (length - 50)) {
OWI_KickWdt();
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;
}
r->read_len++;
}
OWI_StopRead();
OWI_KickWdt();
}