keil/include/board/board.c
@@ -1,5 +1,5 @@
/*
 * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
 * Copyright (c) 2019-2025 Beijing Hanwei Innovation Technology Ltd. Co. and
 * its subsidiaries and affiliates (collectly called MKSEMI).
 *
 * All rights reserved.
@@ -42,10 +42,16 @@
#include "mk_power.h"
#include "mk_clock.h"
#include "mk_calib.h"
#include "mk_reset.h"
#include "mk_misc.h"
#include "mk_rtc.h"
#ifdef UWB_EN
#include "mk_uwb.h"
#ifdef WSF_EN
#include "wsf_nvm.h"
#include "mk_nvm.h"
#endif
#if (X38M4_AUTO_TUNE_EN == 2)
#include "mk_adc.h"
#include <math.h>
#endif
#if defined(UCI_INTF_PORT)
#include "uci_tl_task.h"
@@ -53,10 +59,6 @@
#if TRACE_EN
static enum TRACE_PORT_T user_trace_port;
#endif
#ifndef TRACE_BAUD_RATE
#define TRACE_BAUD_RATE (BAUD_115200)
#endif
struct BOARD_PARAM_T board_param = {0};
@@ -82,7 +84,7 @@
    calib_check(CALIB_REFPLL_DONE);
    calib_close();
    /* SYSCLK comes from XTAL */
    /* SYSCLK comes from XTAL 38.4M */
    clock_attach(SYS_CLK_SOURCE);
    /* Configure AHB clock, AHBCLK = SYSCLK/(div) */
@@ -97,10 +99,9 @@
    /* Select WDT clcok source: 32K or APBCLK */
    clock_attach(CLOCK_32K_TO_WDT_CLK);
#if SYS_TICK_EN
    /* Configure sys tick timer, 32768 / 100 = 10ms @ 32k */
    sys_tick_start(328);
#endif
    /* reset and config rtc for rtc_us() and mk_timer_list */
    reset_module(RESET_MODULE_RTC);
    rtc_open(RTC_ID0, 0);
    /* System timer */
    sys_timer_open();
@@ -112,8 +113,8 @@
    trace_open(port, TRACE_BAUD_RATE);
    user_trace_port = port;
#endif
//    LOG_INFO(TRACE_MODULE_APP, "Hello from MKSEMI!\r\n");
//    LOG_INFO(TRACE_MODULE_APP, "Build information %s\r\n", mk_build_inf);
    LOG_INFO(TRACE_MODULE_APP, "Hello from MKSEMI!\r\n");
    LOG_INFO(TRACE_MODULE_APP, "Build information %s\r\n", mk_build_inf);
}
//修改波特率函数
void board_debug_console_open_baud(enum TRACE_PORT_T port,enum UART_BAUD_T baud_rate)
@@ -123,10 +124,12 @@
    user_trace_port = port;
#endif
}
void board_calibration_params_default(void)
{
    board_param.load_cap = 76;
    board_param.x38m4_load_cap = 76;
    board_param.vdd_core_vol = 0x2;
    board_param.loopback_time = 0;
#ifdef UWB_EN
    board_param.tx_power_fcc[CALIB_CH9] = TX_POWER_LEVEL;
    board_param.tx_power_fcc[CALIB_CH5] = TX_POWER_LEVEL;
@@ -137,19 +140,17 @@
    board_param.peer_short_addr = 0;
#if (ANT_PATTERN == ANT_PATTERN_SQUARE)
    int16_t ant_delays_ch9[4] = {0, 0, 0, 36};
    int16_t ant_delays_ch5[4] = {0, 0, 0, 36};
    int16_t ant_delays_ch2[4] = {0, 0, 36, 0};
    int16_t ant_delays_ch9[4] = {106, 106, 106, 106};
    int16_t ant_delays_ch5[4] = {106, 106, 106, 106};
    int16_t ant_delays_ch2[4] = {106, 106, 106, 106};
    // 4-ANTs: 0, 1, 2, 3
    int16_t pdoa_delays_ch9[4] = {52, -21, -8, 0};
    int16_t pdoa_delays_ch5[4] = {52, -21, -8, 0};
    // int16_t pdoa_delays_ch5[4] = {70, -2, -0, 0};
    int16_t pdoa_delays_ch2[4] = {52, -21, -8, 0};
    int16_t pdoa_gains_ch9[4] = {94, 99, 89, 88};
    int16_t pdoa_gains_ch5[4] = {94, 99, 89, 88};
    // int16_t pdoa_gains_ch5[4] = {94, 93, 89, 98};
    int16_t pdoa_gains_ch2[4] = {94, 99, 89, 88};
    int16_t pdoa_offsets[2] = {0, 0};
@@ -157,9 +158,9 @@
#elif (ANT_PATTERN == ANT_PATTERN_TRIANGLE_REGULAR)
    int16_t ant_delays_ch9[4] = {0, 0, 0, 36};
    int16_t ant_delays_ch5[4] = {0, 0, 0, 36};
    int16_t ant_delays_ch2[4] = {0, 0, 36, 0};
    int16_t ant_delays_ch9[4] = {106, 106, 106, 106};
    int16_t ant_delays_ch5[4] = {106, 106, 106, 106};
    int16_t ant_delays_ch2[4] = {106, 106, 106, 106};
    // 3-ANTs: 3, 0, 1
    int16_t pdoa_delays_ch9[4] = {0, -21, 52};
@@ -176,9 +177,9 @@
#else
    // linear antenna array
    int16_t ant_delays_ch9[4] = {0, 0, 0, 122};
    int16_t ant_delays_ch5[4] = {0, 0, 0, 122};
    int16_t ant_delays_ch2[4] = {0, 0, 122, 0};
    int16_t ant_delays_ch9[4] = {152, 152, 152, 152};
    int16_t ant_delays_ch5[4] = {170, 170, 170, 170};
    int16_t ant_delays_ch2[4] = {170, 170, 170, 170};
#if RX_ANT_PORTS_NUM == 4
    // 4-ANTs: 0, 1, 2, 3
@@ -192,6 +193,9 @@
    int16_t pdoa_offsets[2] = {0, 0};
    board_param.pdoa_ant_space = 180;
    board_param.angle_correction[0] = 1122;
    board_param.angle_correction[1] = 3;
#elif RX_ANT_PORTS_NUM == 3
@@ -217,6 +221,9 @@
    int16_t pdoa_offsets[2] = {0, 0};
    board_param.pdoa_ant_space = 180;
    board_param.angle_correction[0] = 1229;
    board_param.angle_correction[1] = 14;
#elif RX_ANT_PORTS_NUM == 2
#if 0
@@ -240,6 +247,15 @@
#endif
    int16_t pdoa_offsets[2] = {0, 0};
    board_param.pdoa_ant_space = 180;
    board_param.angle_correction[0] = 1049;
    board_param.angle_correction[1] = -32;
    board_param.angle_correction[2] = -46;
    board_param.angle_correction[3] = 3714;
    board_param.angle_correction[4] = 103;
    board_param.angle_correction[5] = -131;
    board_param.angle_correction[6] = 872;
    board_param.angle_correction[7] = -283;
#endif
#endif
@@ -265,73 +281,112 @@
#endif
}
void board_calibration_params_load(void)
#ifdef UWB_EN
static void load_params_from_nvm(void)
{
    board_calibration_params_default();
#ifdef WSF_EN
    if (TRUE == WsfNvmReadData(BOARD_LOAD_CAP, &board_param.load_cap, sizeof(board_param.load_cap), 0))
    if (true == mk_nvm_read(BOARD_X38M4_LOAD_CAP, &board_param.x38m4_load_cap, sizeof(board_param.x38m4_load_cap)))
    {
        board_param.flag |= (1 << BOARD_LOAD_CAP);
        board_param.flag |= (1 << BOARD_X38M4_LOAD_CAP);
    }
    if (TRUE == WsfNvmReadData(BOARD_TX_POWER_FCC_LEVEL, &board_param.tx_power_fcc[0], sizeof(board_param.tx_power_fcc), 0))
    if (true == mk_nvm_read(BOARD_TX_POWER_FCC_LEVEL, &board_param.tx_power_fcc[0], sizeof(board_param.tx_power_fcc)))
    {
        board_param.flag |= (1 << BOARD_TX_POWER_FCC_LEVEL);
    }
    if (TRUE == WsfNvmReadData(BOARD_RANGING_SESSION_ID, (uint8_t *)&board_param.ranging_session_id, sizeof(board_param.ranging_session_id), 0))
    if (true == mk_nvm_read(BOARD_RANGING_SESSION_ID, (uint8_t *)&board_param.ranging_session_id, sizeof(board_param.ranging_session_id)))
    {
        board_param.flag |= (1 << BOARD_RANGING_SESSION_ID);
    }
    if (TRUE == WsfNvmReadData(BOARD_LOCAL_SHORT_ADDR, (uint8_t *)&board_param.local_short_addr, sizeof(board_param.local_short_addr), 0))
    if (true == mk_nvm_read(BOARD_LOCAL_SHORT_ADDR, (uint8_t *)&board_param.local_short_addr, sizeof(board_param.local_short_addr)))
    {
        board_param.flag |= (1 << BOARD_LOCAL_SHORT_ADDR);
    }
    if (TRUE == WsfNvmReadData(BOARD_PEER_SHORT_ADDR, (uint8_t *)&board_param.peer_short_addr, sizeof(board_param.peer_short_addr), 0))
    if (true == mk_nvm_read(BOARD_PEER_SHORT_ADDR, (uint8_t *)&board_param.peer_short_addr, sizeof(board_param.peer_short_addr)))
    {
        board_param.flag |= (1 << BOARD_PEER_SHORT_ADDR);
    }
    if (TRUE == WsfNvmReadData(BOARD_ANT_DELAYS, (uint8_t *)&board_param.ant_delays[0], sizeof(board_param.ant_delays), 0))
    if (true == mk_nvm_read(BOARD_ANT_DELAYS, (uint8_t *)&board_param.ant_delays[0], sizeof(board_param.ant_delays)))
    {
        board_param.flag |= (1 << BOARD_ANT_DELAYS);
    }
    if (TRUE == WsfNvmReadData(BOARD_PDOA_DELAYS, (uint8_t *)&board_param.pdoa_delays[0], sizeof(board_param.pdoa_delays), 0))
    if (true == mk_nvm_read(BOARD_PDOA_DELAYS, (uint8_t *)&board_param.pdoa_delays[0], sizeof(board_param.pdoa_delays)))
    {
        board_param.flag |= (1 << BOARD_PDOA_DELAYS);
    }
    if (TRUE == WsfNvmReadData(BOARD_PDOA_GAINS, (uint8_t *)&board_param.pdoa_gains[0], sizeof(board_param.pdoa_gains), 0))
    if (true == mk_nvm_read(BOARD_PDOA_GAINS, (uint8_t *)&board_param.pdoa_gains[0], sizeof(board_param.pdoa_gains)))
    {
        board_param.flag |= (1 << BOARD_PDOA_GAINS);
    }
    if (TRUE == WsfNvmReadData(BOARD_PDOA_ANT_SPACE, (uint8_t *)&board_param.pdoa_ant_space, sizeof(board_param.pdoa_ant_space), 0))
    if (true == mk_nvm_read(BOARD_PDOA_ANT_SPACE, (uint8_t *)&board_param.pdoa_ant_space, sizeof(board_param.pdoa_ant_space)))
    {
        board_param.flag |= (1 << BOARD_PDOA_ANT_SPACE);
    }
    if (TRUE == WsfNvmReadData(BOARD_PDOA_OFFSETS, (uint8_t *)&board_param.pdoa_offsets[0], sizeof(board_param.pdoa_offsets), 0))
    if (true == mk_nvm_read(BOARD_PDOA_OFFSETS, (uint8_t *)&board_param.pdoa_offsets[0], sizeof(board_param.pdoa_offsets)))
    {
        board_param.flag |= (1 << BOARD_PDOA_OFFSETS);
    }
    if (TRUE == WsfNvmReadData(BOARD_DEV_ROLE, (uint8_t *)&board_param.dev_role, sizeof(board_param.dev_role), 0))
    if (true == mk_nvm_read(BOARD_DEV_ROLE, (uint8_t *)&board_param.dev_role, sizeof(board_param.dev_role)))
    {
        board_param.flag |= (1 << BOARD_DEV_ROLE);
    }
    if (TRUE == WsfNvmReadData(BOARD_DEV_ROLE_IDX, (uint8_t *)&board_param.dev_role_idx, sizeof(board_param.dev_role_idx), 0))
    if (true == mk_nvm_read(BOARD_DEV_ROLE_IDX, (uint8_t *)&board_param.dev_role_idx, sizeof(board_param.dev_role_idx)))
    {
        board_param.flag |= (1 << BOARD_DEV_ROLE_IDX);
    }
    if (TRUE == WsfNvmReadData(BOARD_X32K_LOAD_CAP, &board_param.x32k_load_cap, sizeof(board_param.x32k_load_cap), 0))
    if (true == mk_nvm_read(BOARD_X32K_LOAD_CAP, &board_param.x32k_load_cap, sizeof(board_param.x32k_load_cap)))
    {
        board_param.flag |= (1 << BOARD_X32K_LOAD_CAP);
    }
    if (true == mk_nvm_read(BOARD_CALIB_X38M4_TEMPERATURE, (uint8_t *)&board_param.calib_x38m4_temperature, sizeof(board_param.calib_x38m4_temperature)))
    {
        board_param.flag |= (1 << BOARD_CALIB_X38M4_TEMPERATURE);
    }
    if (true == mk_nvm_read(BOARD_CALIB_X38M4_PPM, (uint8_t *)&board_param.calib_x38m4_ppm, sizeof(board_param.calib_x38m4_ppm)))
    {
        board_param.flag |= (1 << BOARD_CALIB_X38M4_PPM);
    }
    if (true == mk_nvm_read(BOARD_ANGLE_CORRECTION, (uint8_t *)&board_param.angle_correction, sizeof(board_param.angle_correction)))
    {
        board_param.flag |= (1 << BOARD_ANGLE_CORRECTION);
    }
    if (true == mk_nvm_read(BOARD_VDD_CORE_VOL, &board_param.vdd_core_vol, sizeof(board_param.vdd_core_vol)))
    {
        board_param.flag |= (1 << BOARD_VDD_CORE_VOL);
    }
    if (true == mk_nvm_read(BOARD_LOOPBACK_TIME, (uint8_t *)&board_param.loopback_time, sizeof(board_param.loopback_time)))
    {
        board_param.flag |= (1 << BOARD_LOOPBACK_TIME);
    }
}
#endif
void board_calibration_params_load(void)
{
    board_calibration_params_default();
#ifdef UWB_EN
    uint32_t internal_flash = (REG_READ(0x40000018) >> 17) & 0x1;
    uint32_t external_flash = (REG_READ(0x40010030) >> 28) & 0x3;
    if (internal_flash || external_flash == 1)
    {
        mk_nvm_init();
        load_params_from_nvm();
        flash_close(FLASH_ID0);
    }
#endif
}
@@ -339,8 +394,8 @@
uint8_t board_calibration_param_write(uint8_t id, uint8_t *param, uint8_t param_len)
{
    uint8_t ret = 0;
#ifdef WSF_EN
    if (((id == BOARD_LOAD_CAP) && (param_len == sizeof(board_param.load_cap))) ||
#ifdef UWB_EN
    if (((id == BOARD_X38M4_LOAD_CAP) && (param_len == sizeof(board_param.x38m4_load_cap))) ||
        ((id == BOARD_TX_POWER_FCC_LEVEL) && (param_len == sizeof(board_param.tx_power_fcc))) ||
        ((id == BOARD_RANGING_SESSION_ID) && (param_len == sizeof(board_param.ranging_session_id))) ||
        ((id == BOARD_LOCAL_SHORT_ADDR) && (param_len == sizeof(board_param.local_short_addr))) ||
@@ -352,9 +407,14 @@
        ((id == BOARD_PDOA_OFFSETS) && (param_len == sizeof(board_param.pdoa_offsets))) ||
        ((id == BOARD_DEV_ROLE) && (param_len == sizeof(board_param.dev_role))) ||
        ((id == BOARD_DEV_ROLE_IDX) && (param_len == sizeof(board_param.dev_role_idx))) ||
        ((id == BOARD_X32K_LOAD_CAP) && (param_len == sizeof(board_param.x32k_load_cap))))
        ((id == BOARD_X32K_LOAD_CAP) && (param_len == sizeof(board_param.x32k_load_cap))) ||
        ((id == BOARD_CALIB_X38M4_TEMPERATURE) && (param_len == sizeof(board_param.calib_x38m4_temperature))) ||
        ((id == BOARD_CALIB_X38M4_PPM) && (param_len == sizeof(board_param.calib_x38m4_ppm))) ||
        ((id == BOARD_ANGLE_CORRECTION) && (param_len == sizeof(board_param.angle_correction))) ||
        ((id == BOARD_VDD_CORE_VOL) && (param_len == sizeof(board_param.vdd_core_vol))) ||
        ((id == BOARD_LOOPBACK_TIME) && (param_len == sizeof(board_param.loopback_time))))
    {
        ret = WsfNvmWriteData(id, param, param_len, 0);
        ret = mk_nvm_write(id, param, param_len);
    }
#endif
    return ret;
@@ -366,7 +426,7 @@
    {
        return;
    }
#ifdef UWB_EN
#if (ANT_PATTERN == ANT_PATTERN_SQUARE) // 3D
#elif (ANT_PATTERN == ANT_PATTERN_TRIANGLE_REGULAR) // 3D
@@ -374,32 +434,33 @@
#elif (ANT_PATTERN == ANT_PATTERN_LINEAR) // 2D -90 ~ 90
    // azimuth correction
    float post_azimuth = mk_q7_to_f32(*azimuth);
#if RX_ANT_PORTS_NUM == 4
    post_azimuth = (int16_t)(1.1221f * post_azimuth + 0.2729f);
#elif RX_ANT_PORTS_NUM == 3
    post_azimuth = (int16_t)(1.2287f * post_azimuth + 1.3633f);
#elif RX_ANT_PORTS_NUM == 2
    if (post_azimuth < -13.1)
    if (board_param.angle_correction[0])
    {
        post_azimuth = (int16_t)(0.8719f * post_azimuth - 28.282f);
    }
    else if (post_azimuth < -4.6)
    {
        post_azimuth = (int16_t)(3.7137f * post_azimuth + 10.307f);
    }
    else
    {
        post_azimuth = (int16_t)(1.0492f * post_azimuth - 3.1928f);
        float k, b;
        if (board_param.angle_correction[6] && post_azimuth < 0.1f * board_param.angle_correction[5])
        {
            k = board_param.angle_correction[6] * 0.001f;
            b = board_param.angle_correction[7] * 0.1f;
        }
        else if (board_param.angle_correction[3] && post_azimuth < 0.1f * board_param.angle_correction[2])
        {
            k = board_param.angle_correction[3] * 0.001f;
            b = board_param.angle_correction[4] * 0.1f;
        }
        else
        {
            k = board_param.angle_correction[0] * 0.001f;
            b = board_param.angle_correction[1] * 0.1f;
        }
        post_azimuth = (int16_t)(k * post_azimuth + b);
    }
#endif
    post_azimuth = ((post_azimuth > 90) ? 90 : ((post_azimuth < -90) ? -90 : post_azimuth));
    *azimuth = mk_f32_to_q7(post_azimuth);
#endif
#endif
}
void board_5V_input_init(GPIO_IRQ_HANDLER_T irq_handler)
@@ -434,11 +495,195 @@
   gpio_enable_irq(PCA_INPUT_DETECT, GPIO_IRQ_TYPE_FALLING_EDGE, pca_input_detect_irq_handler);
   power_wakeup_enable((enum POWER_WAKEUP_SOURCE_T)PCA_INPUT_DETECT, POWER_WAKEUP_LEVEL_LOW);
}
#if (X38M4_AUTO_TUNE_EN == 2)
#if (X38M4_AUTO_TUNE_CENTER_TYPE == 0)
static int32_t ppm_calculate(int16_t temp)
{
    // TZ3398B TC Curve
    int32_t ppm = (int32_t)((1E-04 * pow(temp, 3) - 0.0084 * pow(temp, 2) - 0.1957 * temp + 8.6575) * 100);
    LOG_INFO(TRACE_MODULE_APP, "temp %d, ppm %d\r\n", temp, ppm);
    return ppm;
}
#elif (X38M4_AUTO_TUNE_CENTER_TYPE == 1)
static void board_x38m4_ppm_detected_init(void)
{
    gpio_pin_set_dir(IO_PIN_1, GPIO_DIR_OUT, 1);
    static struct ADC_CFG_T usr_adc_cfg = {
        .mode = ADC_MODE_CONTINUE,    /* Selected single conversion mode  */
        .clk_sel = ADC_CLK_HIGH,      /* Selected 62.4M high speed clock */
        .vref_sel = ADC_SEL_VREF_EXT, /* Using external reference voltage (3.3V)*/
        .rate = 1000000,              /* ADC works at high frequency system clock, the maximum sampling rate is 2M */
        .channel_p = ADC_IN_EXTPIN0,  /* ADC positive channel --> GPIO0 */
        .channel_n = ADC_IN_GUD,      /* ADC negative channel --> GND */
        .int_en = false,
        .dma_en = false, /* DMA support only in continue mode */
        .acc_num = 0,
        .high_pulse_time = 4,
        .settle_time = 1,
    };
    adc_open(&usr_adc_cfg);
}
static void board_x38m4_ppm_detected_close(void)
{
    adc_close();
    gpio_pin_set_dir(IO_PIN_1, GPIO_DIR_OUT, 0);
}
static int32_t ppm_calculate(int16_t temp)
{
    // TXC P/N: AF38470002
    int32_t ppm = (int32_t)((9E-05 * pow(temp, 3) - 0.0085 * pow(temp, 2) + 0.0072 * temp + 4.7202) * 100);
    return ppm;
}
#endif
#endif
int32_t board_x38m4_ppm_get(int32_t *p_ppm)
{
#if (X38M4_AUTO_TUNE_EN == 2)
#if (X38M4_AUTO_TUNE_CENTER_TYPE == 0)
    temp_sensor_open();
    int16_t temp = temp_sensor_get(0);
    // LOG_INFO(TRACE_MODULE_APP, "Chip temperature: %d degree\r\n", temp);
    temp_sensor_close();
#define TEMP_CACHE_NUM 10
    static int16_t temp_cache[TEMP_CACHE_NUM] = {0};
    static uint8_t temp_cnt = 0;
    temp_cache[temp_cnt % TEMP_CACHE_NUM] = temp;
    temp_cnt += 1;
    uint8_t temp_num = temp_cnt >= TEMP_CACHE_NUM ? TEMP_CACHE_NUM : temp_cnt;
    int16_t sum_temp = 0;
    for (uint8_t ii = 0; ii < temp_num; ii++)
    {
        sum_temp += temp_cache[ii];
    }
    temp = (uint8_t)(sum_temp / temp_num);
    LOG_INFO(TRACE_MODULE_APP, "temp[%d] %d %d %d %d %d, average %d\r\n", temp_num, temp_cache[0], temp_cache[1], temp_cache[2], temp_cache[3], temp_cache[4],
             sum_temp);
    int32_t ppm_calib = ppm_calculate(board_param.calib_x38m4_temperature);
    int32_t ppm = ppm_calculate(temp);
    if (p_ppm)
    {
        *p_ppm = ppm - ppm_calib;
    }
    LOG_INFO(TRACE_MODULE_APP, "ppm_get(%d) %d, ppm_calib(%d) %d, ppm offset %d\r\n", temp, ppm, board_param.calib_x38m4_temperature, ppm_calib, *p_ppm);
    return DRV_OK;
#elif (X38M4_AUTO_TUNE_CENTER_TYPE == 1)
// this function vill cost 148us without log print
#define SAMPLE_NUM 3
#define RESISTANCE_REF_VALUE 130 * 1000 // Ohm
#define ADC_EXTERNAL_VREF_MV 3300       // 3300 - 3.3V
#define X38M4_WORK_MIN_TEMP (-40)
    uint32_t adc_sample[SAMPLE_NUM] = {0};
    // adc sample
    board_x38m4_ppm_detected_init();
    int32_t ret = adc_get(&adc_sample[0], SAMPLE_NUM, 0);
    if (ret == DRV_OK)
    {
        uint32_t adc_sum = 0;
        for (uint16_t ii = 0; ii < SAMPLE_NUM; ii++)
        {
            adc_sum += adc_sample[ii];
        }
        adc_sum /= SAMPLE_NUM;
        LOG_INFO(TRACE_MODULE_APP, "adc value[%d] %d %d %d\r\n", SAMPLE_NUM, adc_sample[0], adc_sample[1], adc_sample[2]);
        int16_t tmp_mv = adc_code_to_mv((int16_t)adc_sum, ADC_EXTERNAL_VREF_MV);
        int32_t resistance_val = tmp_mv * RESISTANCE_REF_VALUE / (ADC_EXTERNAL_VREF_MV - tmp_mv);
        // resistance_val = 75658;
        // The temperature value is obtained from the thermistor resistance value
        // the fisrt value means the current temperature is X38M4_WORK_MIN_TEMP, the second is (X38M4_WORK_MIN_TEMP+1)
        // unit is Ohm
        // TXC P/N: AF38470002
        const int32_t rt_table[] = {
            4397120, 4092870, 3811720, 3551750, 3311240, 3088600, 2882400, 2691310, 2514140, 2349780, 2197230, 2055560, 1923930, 1801570, 1687770, 1581880,
            1483100, 1391110, 1305410, 1225530, 1151040, 1081540, 1016660, 956080,  899480,  846580,  797110,  750830,  707520,  666970,  628990,  593340,
            559930,  528600,  499210,  471630,  445770,  421480,  398650,  377190,  357010,  338010,  320120,  303290,  287430,  272500,  258430,  245160,
            232650,  220850,  209710,  199200,  189270,  17989,   171030,  162650,  154730,  147230,  140140,  133430,  127080,  121070,  115370,  109970,
            104850,  100000,  95400,   91030,   86890,   82960,   79220,   75680,   72310,   69100,   66060,   63170,   60420,   57800,   55310,   52930,
            50680,   48530,   46480,   44530,   42670,   40900,   39210,   37600,   36060,   34600,   33190,   31860,   30580,   29370,   28200,   27090,
            26030,   25010,   24040,   23110,   22220,   21370,   20560,   19780,   19040,   18320,   17640,   16990,   16360,   15760,   15180,   14630,
            14100,   13590,   13100,   12640,   12190,   11760,   11340,   10950,   10570,   10200,   9850,    9510,    9180,    8870,    8570,    8280,
            8010,    7740,    7480,    7230,    7000,    6770,    6550,    6340,    6130,    5930,    5740,    5560,    5380,    5210,    5050,    4890,
            4740,    4590,    4450,    4320,    4180,    4060,    3930,    3820,    3700,    3590,    3480,    3380,    3280,    3190,    3090,    3000,
            2920,    2830,    2750,    2670,    2600,    2520};
        const uint16_t num_rt = sizeof(rt_table) / sizeof(int32_t);
        int16_t temp = X38M4_WORK_MIN_TEMP - 1;
        for (int16_t ii = 0; ii < num_rt; ii++)
        {
            int32_t delta_rt_0 = 0;
            int32_t delta_rt_1 = 0;
            if (ii == 0)
            {
                delta_rt_1 = (rt_table[ii] - rt_table[ii + 1]) / 2;
                delta_rt_0 = delta_rt_1;
            }
            else if (ii == (num_rt - 1))
            {
                delta_rt_0 = (rt_table[ii - 1] - rt_table[ii]) / 2;
                delta_rt_1 = delta_rt_0;
            }
            else
            {
                delta_rt_0 = (rt_table[ii - 1] - rt_table[ii]) / 2;
                delta_rt_1 = (rt_table[ii] - rt_table[ii + 1]) / 2;
            }
            // LOG_INFO(TRACE_MODULE_APP, "[%d] %d %d %d\r\n", ii, rt_table[ii] + delta_rt_0, resistance_val, rt_table[ii] - delta_rt_1);
            // if ((rt_table[ii] + delta_rt_0) > resistance_val >= (rt_table[ii] - delta_rt_1))
            if (resistance_val >= (rt_table[ii] - delta_rt_1) && resistance_val < (rt_table[ii] + delta_rt_0))
            {
                temp = X38M4_WORK_MIN_TEMP + ii;
                break;
            }
        }
        // The crystal frequency offset is obtained by temperature
        if (temp >= X38M4_WORK_MIN_TEMP && (board_param.flag & (1 << BOARD_CALIB_X38M4_TEMPERATURE)))
        {
            int32_t ppm_calib = ppm_calculate(board_param.calib_x38m4_temperature);
            int32_t ppm = ppm_calculate(temp);
            if (p_ppm)
            {
                *p_ppm = ppm - ppm_calib;
            }
            LOG_INFO(TRACE_MODULE_APP, "ppm_get(%d) %d, ppm_calib(%d) %d\r\n", temp, ppm, board_param.calib_x38m4_temperature, ppm_calib);
        }
        else
        {
            ret = DRV_DEV_UNAVAILABLE;
        }
        LOG_INFO(TRACE_MODULE_APP, "board_x38m4_ppm_get average %d, volatage %d, resistance %d, temperature %d, ppm offset %d\r\n", adc_sum, tmp_mv,
                 resistance_val, temp, *p_ppm);
    }
    board_x38m4_ppm_detected_close();
    return ret;
#endif
#else
    return DRV_OK;
#endif
}
void board_button_init(GPIO_IRQ_HANDLER_T irq_handler)
{
    button_irq_handler = irq_handler;
    gpio_pin_set_dir(BOARD_SW_1, GPIO_DIR_IN, 0);
    io_pull_set(BOARD_SW_1, IO_PULL_UP, IO_PULL_UP_LEVEL3);
    io_pull_set(BOARD_SW_1, IO_PULL_UP, IO_PULL_UP_LEVEL4);
    gpio_enable_irq(BOARD_SW_1, GPIO_IRQ_TYPE_FALLING_EDGE, button_irq_handler);
    power_wakeup_enable((enum POWER_WAKEUP_SOURCE_T)BOARD_SW_1, POWER_WAKEUP_LEVEL_LOW);
@@ -447,7 +692,7 @@
void board_led_init(void)
{
    gpio_pin_set_dir(BOARD_LED_1, GPIO_DIR_OUT, 0);
//    gpio_pin_set_dir(BOARD_LED_2, GPIO_DIR_OUT, 0);
    gpio_pin_set_dir(BOARD_LED_2, GPIO_DIR_OUT, 0);
}
void board_led_on(enum IO_PIN_T idx)
@@ -474,6 +719,13 @@
}
void board_configure(void)
{
#if (X38M4_AUTO_TUNE_EN == 2)
    int32_t ppm_offset = 0;
    if (board_x38m4_ppm_get(&ppm_offset) == DRV_OK)
    {
        calib_xtal38m4_load_cap_auto_tune_to_center(ppm_offset + board_param.calib_x38m4_ppm, board_param.x38m4_load_cap);
    }
#endif
}
void board_prepare_for_power_down(void)
@@ -495,7 +747,7 @@
    uci_tl_resume();
#else
    // button - restore interrupt type
   gpio_enable_irq(PCA_INPUT_DETECT, GPIO_IRQ_TYPE_FALLING_EDGE, pca_input_detect_irq_handler);
   gpio_enable_irq(PCA_INPUT_DETECT, GPIO_IRQ_TYPE_FALLING_EDGE, pca_input_detect_irq_handler);
   gpio_enable_irq(ACCLERATE_DETECT_Pin, GPIO_IRQ_TYPE_RISING_EDGE, accelerate_irq_handler);
//    if (button_irq_handler)
//    {