Compare commits

...

2 Commits

  1. 596
      1/owi.c
  2. 602
      2/owi.c
  3. 666
      3/owi.c
  4. BIN
      DefaultBuild/app_owi_service.obj
  5. BIN
      DefaultBuild/multical.abs
  6. 736
      DefaultBuild/multical.map
  7. 3494
      DefaultBuild/multical.mot
  8. BIN
      DefaultBuild/owi.obj
  9. BIN
      DefaultBuild/r_cg_serial_user.obj
  10. BIN
      DefaultBuild/r_main.obj
  11. BIN
      DefaultBuild/uart.obj
  12. 55
      QualityReport(multical,DefaultBuild).txt
  13. 83
      app_owi_service.c
  14. 112
      multical.temp.mtud
  15. 28
      owi.c
  16. 79
      r_main.c
  17. 3
      uart.c

596
1/owi.c

@ -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);
}

602
2/owi.c

@ -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);
}

666
3/owi.c

@ -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);
}

BIN
DefaultBuild/app_owi_service.obj

Binary file not shown.

BIN
DefaultBuild/multical.abs

Binary file not shown.

736
DefaultBuild/multical.map

File diff suppressed because it is too large

3494
DefaultBuild/multical.mot

File diff suppressed because it is too large

BIN
DefaultBuild/owi.obj

Binary file not shown.

BIN
DefaultBuild/r_cg_serial_user.obj

Binary file not shown.

BIN
DefaultBuild/r_main.obj

Binary file not shown.

BIN
DefaultBuild/uart.obj

Binary file not shown.

55
QualityReport(multical,DefaultBuild).txt

@ -1,7 +1,38 @@
QualityReport
2026년 5월 22일 금요일 오전 9:15:29
2026년 7월 30일 목요일 오전 9:19:08
------ Start build(multical, DefaultBuild) ------
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\Bin\ccrl.exe r_main.c -cpu=S3 -o DefaultBuild\r_main.obj "-dev=C:\Program Files (x86)\Renesas Electronics\CS+\CC\Device\RL78\Devicefile\DR5F10PPJ.DVF" -g -g_line -I "..\..\Documents\카카오톡 받은 파일\IDH1.1\IDH1.1" -I ..\IDH1.1 -I . -c -msg_lang=english
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\Bin\ccrl.exe app_owi_service.c -cpu=S3 -o DefaultBuild\app_owi_service.obj "-dev=C:\Program Files (x86)\Renesas Electronics\CS+\CC\Device\RL78\Devicefile\DR5F10PPJ.DVF" -g -g_line -I "..\..\Documents\카카오톡 받은 파일\IDH1.1\IDH1.1" -I ..\IDH1.1 -I . -c -msg_lang=english
W0511106:The folder "..\..\Documents\카카오톡 받은 파일\IDH1.1\IDH1.1" specified by the "-I" option is not found.
W0511106:The folder "..\..\Documents\카카오톡 받은 파일\IDH1.1\IDH1.1" specified by the "-I" option is not found.
W0511187:The evaluation period for the option "-Odefault" of CC-RL V1 has expired. It is implicitly changed to "-Olite". Please consider purchasing the product to continue using "-Odefault". By explicitly specifying "-Olite" or "-Onothing", this warning message disappears.
W0511187:The evaluation period for the option "-Odefault" of CC-RL V1 has expired. It is implicitly changed to "-Olite". Please consider purchasing the product to continue using "-Odefault". By explicitly specifying "-Olite" or "-Onothing", this warning message disappears.
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(18):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(19):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(20):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(25):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(26):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(27):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(18):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(19):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(20):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(25):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(26):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(27):W0520301:Typedef name has already been declared (with same type)
i2c.h(8):W0520047:Incompatible redefinition of macro "RAM_BYTES" (declared at line 15 of "uart.h")
r_main.c(692):W0520172:External/internal linkage conflict with previous declaration
r_main.c(811):W0520177:Variable "dbg" was declared but never referenced
r_main.c(1302):W0520177:Variable "dbg" was declared but never referenced
r_main.c(1933):W0520177:Variable "total_us" was declared but never referenced
r_main.c(1934):W0520177:Variable "idle_us" was declared but never referenced
r_main.c(1936):W0520177:Variable "got_any" was declared but never referenced
r_main.c(102):W0520177:Variable "s_end_pat" was declared but never referenced
r_main.c(268):W0520177:Function "UART1_SendBytes_Safe" was declared but never referenced
r_main.c(429):W0520177:Function "bridge_wait_until_end" was declared but never referenced
r_main.c(770):W0520177:Function "connect_verify_reset" was declared but never referenced
r_main.c(775):W0520177:Function "print_hex_line" was declared but never referenced
r_main.c(1637):W0520177:Function "execute_owi_service_from_line" was declared but never referenced
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\Bin\ccrl.exe owi.c -cpu=S3 -o DefaultBuild\owi.obj "-dev=C:\Program Files (x86)\Renesas Electronics\CS+\CC\Device\RL78\Devicefile\DR5F10PPJ.DVF" -g -g_line -I "..\..\Documents\카카오톡 받은 파일\IDH1.1\IDH1.1" -I ..\IDH1.1 -I . -c -msg_lang=english
W0511106:The folder "..\..\Documents\카카오톡 받은 파일\IDH1.1\IDH1.1" specified by the "-I" option is not found.
W0511187:The evaluation period for the option "-Odefault" of CC-RL V1 has expired. It is implicitly changed to "-Olite". Please consider purchasing the product to continue using "-Odefault". By explicitly specifying "-Olite" or "-Onothing", this warning message disappears.
@ -12,15 +43,15 @@ C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(25
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(26):W0520301:Typedef name has already been declared (with same type)
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\inc\stdint.h(27):W0520301:Typedef name has already been declared (with same type)
uart.h(15):W0520047:Incompatible redefinition of macro "RAM_BYTES" (declared at line 29 of "owi.h")
owi.c(528):W0520549:Variable "r" is used before its value is set
owi.c(537):W0520549:Variable "r" is used before its value is set
owi.c(142):W0520177:Function "OWI_StopWrite" was declared but never referenced
owi.c(157):W0520177:Function "OWI_WaitFirstBitStart" was declared but never referenced
owi.c(546):W0520549:Variable "r" is used before its value is set
owi.c(143):W0520177:Function "OWI_StopWrite" was declared but never referenced
owi.c(158):W0520177:Function "OWI_WaitFirstBitStart" was declared but never referenced
C:\Program Files (x86)\Renesas Electronics\CS+\CC\CC-RL\V1.15.00\Bin\rlink.exe -subcommand=DefaultBuild\multical.clnk
W0561017:Paid license of CC-RL V1 is not found, and the evaluation period has expired. Please consider purchasing the product.
W0561017:Paid license of CC-RL V1 is not found, and the evaluation period has expired. Please consider purchasing the product.
Renesas Optimizing Linker Completed
------ Build ended(Error:0, Warning:15)(multical, DefaultBuild) ------
------ Build ended(Error:0, Warning:44)(multical, DefaultBuild) ------
--- CommandFile 1 ---
DefaultBuild\multical.clnk :
@ -75,8 +106,8 @@ DefaultBuild\multical.clnk :
--- SHA1 hash value of output files ---
C:\Users\temp\Desktop\new_fw\DefaultBuild\multical.abs: f5b7d3bfe164041f7c436f8167bef7cc17963bf9
C:\Users\temp\Desktop\new_fw\DefaultBuild\multical.mot: 68fb124bcfd8d50a76d54bad4d688fa32526e99b
C:\Users\temp\Desktop\new_fw\DefaultBuild\multical.abs: b7c6b666e469b31beca03f72cf76832a7a7fd1de
C:\Users\temp\Desktop\new_fw\DefaultBuild\multical.mot: ea661bdc3d677102e44160d16233eb2c7f15ec1c
--- System Information ---
@ -87,7 +118,7 @@ C:\Users\temp\Desktop\new_fw\DefaultBuild\multical.mot: 68fb124bcfd8d50a76d54bad
*.NET Framework Version
Microsoft .NET Framework 4 [.NET 4.8 or later] (533325)
*WebView2 Version
148.0.3967.70
150.0.4078.105
--- Application Information ---
*Product Name
@ -104,13 +135,13 @@ C:\Users\temp\Desktop\new_fw\DefaultBuild\multical.mot: 68fb124bcfd8d50a76d54bad
C:\Program Files (x86)\Renesas Electronics\CS+\CC
*Memory Usage
*Private Working Set
366 MB
289 MB
*Number of GDI Objects
2884
2840
*Number of USER Objects
1851
1765
*Opened Files
36 editors, 36 files, 254 KB
36 editors, 36 files, 256 KB
--- Build Tool Plug-in Information ---
RH850 Build tool CC-RH Plug-in

83
app_owi_service.c

@ -4,6 +4,12 @@
#include "r_cg_wdt.h"
#include <string.h>
#define OWI_VERIFIED_MAX_LEN 129u
#define OWI_VERIFIED_127_ATTEMPTS 6u
#define OWI_VERIFIED_129_ATTEMPTS 8u
#define OWI_VERIFIED_FIRST_US 30000u
#define OWI_VERIFIED_RETRY_US 10000u
static app_owi_result_t app_owi_from_raw(const owi_io_result_t *io)
{
app_owi_result_t r;
@ -29,9 +35,74 @@ static app_owi_result_t app_owi_from_raw(const owi_io_result_t *io)
return r;
}
static uint8_t s_verified_long[OWI_VERIFIED_MAX_LEN];
static uint8_t s_verified_long_len = 0u;
static uint8_t is_long_owi_read(int length)
{
return (length == 119 || length == 127) ? 1u : 0u;
return (length == 119) ? 1u : 0u;
}
static app_owi_result_t app_owi_read_verified_long(uint8_t id,
uint8_t length,
uint8_t max_attempts)
{
static uint8_t samples[3][OWI_VERIFIED_MAX_LEN];
owi_io_result_t io;
uint8_t sample_count = 0u;
uint8_t attempt;
uint8_t sample;
uint8_t replace_index = 0u;
memset(&io, 0, sizeof(io));
for (attempt = 0u; attempt < max_attempts; attempt++) {
delay_us((attempt == 0u) ? OWI_VERIFIED_FIRST_US
: OWI_VERIFIED_RETRY_US);
R_WDT_Restart();
OWI_ReadBytesRaw((int)length, id, &io);
R_WDT_Restart();
if (!io.ok || io.timeout || io.read_len < length ||
io.data[0] != 0x26u) {
continue;
}
/* One fresh full read matching a previously verified value is enough. */
if (s_verified_long_len == length &&
memcmp(s_verified_long, io.data, length) == 0) {
return app_owi_from_raw(&io);
}
for (sample = 0u; sample < sample_count; sample++) {
if (memcmp(samples[sample], io.data, length) == 0) {
memcpy(s_verified_long, io.data, length);
s_verified_long_len = length;
return app_owi_from_raw(&io);
}
}
if (sample_count < 3u) {
memcpy(samples[sample_count], io.data, length);
sample_count++;
} else {
/* Keep recent distinct samples so a later stable pair can match. */
memcpy(samples[replace_index], io.data, length);
replace_index++;
if (replace_index >= 3u) {
replace_index = 0u;
}
}
}
/* Do not return a possibly corrupted long sample. */
memset(&io, 0, sizeof(io));
io.ok = 0u;
io.timeout = 1u;
io.timeout_byte_index = 0xFFFEu;
io.timeout_bit_index = 0xFEu;
return app_owi_from_raw(&io);
}
static uint8_t looks_bad_tail(const owi_io_result_t *io)
@ -102,6 +173,16 @@ app_owi_result_t app_owi_read_basic(uint8_t id, int length)
{
owi_io_result_t io;
if (length == 127) {
return app_owi_read_verified_long(id, 127u,
OWI_VERIFIED_127_ATTEMPTS);
}
if (length == 129) {
return app_owi_read_verified_long(id, 129u,
OWI_VERIFIED_129_ATTEMPTS);
}
R_WDT_Restart();
OWI_ReadBytesRaw(length, id, &io);
R_WDT_Restart();

112
multical.temp.mtud

File diff suppressed because one or more lines are too long

28
owi.c

@ -480,16 +480,22 @@ void OWI_ReadBytesRaw(int length, uint8_t id, owi_io_result_t *r)
r->read_len = (uint16_t)length;
OWI_ClearTimeout();
is_long_read = (length >= 119) ? 1u : 0u;
/* 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));
/* 기존 잘 되던 값 유지 */
delay_us(100u);
/*
* 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);
}
/* 첫 falling edge를 한 번 잡는다 */
R_WDT_Restart();
if (!OWI_WaitForFallingEdge(0u, 0u)) {
owi_result_latch_timeout(r);
@ -500,14 +506,14 @@ void OWI_ReadBytesRaw(int length, uint8_t id, owi_io_result_t *r)
for (i = 0; i < length; i++) {
R_WDT_Restart();
/* long read만 주기적 재동기화 */
/* 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_WDT_Restart();
if (!OWI_WaitForFallingEdge((uint16_t)i, 0u)) {
owi_result_latch_timeout(r);
break;
}
}
r->data[i] = OWI_ReadByte_StreamSynced((uint16_t)i);

79
r_main.c

@ -341,7 +341,7 @@ static unsigned char hex2byte(char h, char l)
static uint8_t is_long_owi_read_len(uint8_t len)
{
return (len == 119u || len == 127u);
return (len == 119u);
}
static app_owi_result_t do_stable_owi_read(uint8_t id, uint8_t read_len)
@ -941,8 +941,7 @@ static int execute_connect_verify_sequence(CmdSource src, const app_job_t *job)
static int execute_direct_read_sequence(CmdSource src, const app_job_t *job)
{
app_owi_result_t r_write;
app_owi_result_t r_read;
app_owi_result_t r;
uint8_t read_len = 0;
if (!job) return 0;
@ -987,21 +986,22 @@ static int execute_direct_read_sequence(CmdSource src, const app_job_t *job)
return 0;
}
r_write = app_owi_write_basic(0x28u, job->payload, 3);
if (!r_write.ok || r_write.timeout) {
r = app_owi_write_basic(0x28u, job->payload, 3);
if (!r.ok || r.timeout) {
OUT_PRINT(src, "Fail\r\n");
send_end_response(src);
return 1;
}
r_read = do_stable_owi_read(0x28u, read_len);
if (!r_read.ok || r_read.timeout || r_read.read_len < read_len) {
r = do_stable_owi_read(0x28u, read_len);
if (!r.ok || r.timeout || r.read_len < read_len) {
OUT_PRINT(src, "Fail\r\n");
send_end_response(src);
return 1;
}
print_owi_read_result(src, &r_read);
print_owi_read_result(src, &r);
send_end_response(src);
return 1;
}
@ -1426,32 +1426,12 @@ static int execute_shadow_write_copy_nvm_sequence(CmdSource src, const app_job_t
return 1;
}
static int execute_owi_service_from_job(CmdSource src, const app_job_t *job)
static int execute_basic_owi_job(CmdSource src, const app_job_t *job)
{
app_owi_result_t r;
if (!job) return 0;
/* connect */
if (execute_connect_verify_sequence(src, job)) {
return 1;
}
/* nvm, shadow, outmem direct read */
if (execute_direct_read_sequence(src, job)) {
return 1;
}
/* write coefficient */
if (execute_write_coeff_sequence(src, job)) {
return 1;
}
/* shadow_write -> copy nvm */
if (execute_shadow_write_copy_nvm_sequence(src, job)) {
return 1;
}
if (job->addr != g_fixed_addr) return 0;
if (job->channel < 1 || job->channel > 20) {
@ -1485,7 +1465,12 @@ static int execute_owi_service_from_job(CmdSource src, const app_job_t *job)
if (job->type == APP_JOB_PROTO_OR) {
r = app_owi_read_basic(job->id, (int)job->len);
print_owi_read_result(src, &r);
if ((job->len == 127u || job->len == 129u) &&
(!r.ok || r.timeout || r.read_len < job->len)) {
OUT_PRINT(src, "Fail\r\n");
} else {
print_owi_read_result(src, &r);
}
send_end_response(src);
return 1;
}
@ -1495,6 +1480,33 @@ static int execute_owi_service_from_job(CmdSource src, const app_job_t *job)
return 1;
}
static int execute_owi_service_from_job(CmdSource src, const app_job_t *job)
{
if (!job) return 0;
/* connect */
if (execute_connect_verify_sequence(src, job)) {
return 1;
}
/* nvm, shadow, outmem direct read */
if (execute_direct_read_sequence(src, job)) {
return 1;
}
/* write coefficient */
if (execute_write_coeff_sequence(src, job)) {
return 1;
}
/* shadow_write -> copy nvm */
if (execute_shadow_write_copy_nvm_sequence(src, job)) {
return 1;
}
return execute_basic_owi_job(src, job);
}
static void forward_line_rs485_and_bridge(const char *line)
{
static char txbuf[UART_RX_BUF_SIZE + 4];
@ -1772,7 +1784,12 @@ static int execute_owi_service_from_line(CmdSource src, const char *line)
}
r = app_owi_read_basic(id, (int)byte_len);
print_owi_read_result(src, &r);
if ((byte_len == 127u || byte_len == 129u) &&
(!r.ok || r.timeout || r.read_len < byte_len)) {
OUT_PRINT(src, "Fail\r\n");
} else {
print_owi_read_result(src, &r);
}
return 1;
}

3
uart.c

@ -56,7 +56,8 @@ void rs485_recover(void)
/* UART1 송신용 내부 버퍼(스택 포인터 안전) */
static uint8_t s_uart1_txbuf[1024];
static uint8_t s_uart0_txbuf[270];
/* 129 data bytes as HEX plus diagnostics/CRLF. */
static uint8_t s_uart0_txbuf[320];
static volatile uint16_t s_uart0_tx_len = 0;

Loading…
Cancel
Save