/*
|
* Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
|
* its subsidiaries and affiliates (collectly called MKSEMI).
|
*
|
* All rights reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice,
|
* this list of conditions and the following disclaimer.
|
*
|
* 2. Redistributions in binary form, except as embedded into an MKSEMI
|
* integrated circuit in a product or a software update for such product,
|
* must reproduce the above copyright notice, this list of conditions and
|
* the following disclaimer in the documentation and/or other materials
|
* provided with the distribution.
|
*
|
* 3. Neither the name of MKSEMI nor the names of its contributors may be used
|
* to endorse or promote products derived from this software without
|
* specific prior written permission.
|
*
|
* 4. This software, with or without modification, must only be used with a
|
* MKSEMI integrated circuit.
|
*
|
* 5. Any software provided in binary form under this license must not be
|
* reverse engineered, decompiled, modified and/or disassembled.
|
*
|
* THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*/
|
|
#include "board.h"
|
#include "mk_power.h"
|
#include "mk_clock.h"
|
#include "mk_calib.h"
|
#include "mk_misc.h"
|
#ifdef UWB_EN
|
#include "mk_uwb.h"
|
#endif
|
#if (X38M4_AUTO_TUNE_EN == 2)
|
#include "mk_adc.h"
|
#include <math.h>
|
#endif
|
#ifdef WSF_EN
|
#include "wsf_nvm.h"
|
#endif
|
#if defined(UCI_INTF_PORT)
|
#include "uci_tl_task.h"
|
#endif
|
|
#if TRACE_EN
|
static enum TRACE_PORT_T user_trace_port;
|
#endif
|
|
struct BOARD_PARAM_T board_param = {0};
|
static GPIO_IRQ_HANDLER_T button_irq_handler = NULL;
|
|
void board_clock_run(void)
|
{
|
// default load cap
|
REG_WRITE(0x40000048, 76);
|
|
clock_attach(CLOCK_48M_RO_TO_SYS_CLK);
|
delay_us(50);
|
|
// calibrate REFPLL
|
calib_open();
|
calib_start(CALIB_PO_REFPLL_EN);
|
calib_check(CALIB_REFPLL_DONE);
|
calib_close();
|
|
/* SYSCLK comes from XTAL 38.4M */
|
clock_attach(SYS_CLK_SOURCE);
|
|
/* Configure AHB clock, AHBCLK = SYSCLK/(div) */
|
clock_set_divider(CLOCK_AHB_DIV, AHB_DIV);
|
|
/* Configure APB clock, APBCLK = AHBCLK/(div) */
|
clock_set_divider(CLOCK_APB_DIV, APB_DIV);
|
|
/* Select 32k clock source: 32768Hz XTAL or 32000Hz RCO */
|
clock_attach(CLK_32K_SOURCE);
|
|
/* 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
|
|
/* System timer */
|
sys_timer_open();
|
}
|
|
void board_debug_console_open(enum TRACE_PORT_T port)
|
{
|
#if TRACE_EN
|
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);
|
}
|
|
void board_calibration_params_default(void)
|
{
|
board_param.x38m4_load_cap = 76;
|
|
#ifdef UWB_EN
|
board_param.tx_power_fcc[CALIB_CH9] = TX_POWER_LEVEL;
|
board_param.tx_power_fcc[CALIB_CH5] = TX_POWER_LEVEL;
|
board_param.tx_power_fcc[CALIB_CH2] = TX_POWER_LEVEL;
|
|
board_param.ranging_session_id = 0;
|
board_param.local_short_addr = 0;
|
board_param.peer_short_addr = 0;
|
|
#if (ANT_PATTERN == ANT_PATTERN_SQUARE)
|
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_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_ch2[4] = {94, 99, 89, 88};
|
|
int16_t pdoa_offsets[2] = {0, 0};
|
board_param.pdoa_ant_space = 180;
|
|
#elif (ANT_PATTERN == ANT_PATTERN_TRIANGLE_REGULAR)
|
|
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};
|
int16_t pdoa_delays_ch5[4] = {0, -21, 52};
|
int16_t pdoa_delays_ch2[4] = {0, -21, 52};
|
|
int16_t pdoa_gains_ch9[4] = {88, 94, 99};
|
int16_t pdoa_gains_ch5[4] = {88, 94, 99};
|
int16_t pdoa_gains_ch2[4] = {88, 94, 99};
|
|
int16_t pdoa_offsets[2] = {0, 0};
|
board_param.pdoa_ant_space = 180;
|
|
#else
|
// linear antenna array
|
|
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
|
int16_t pdoa_delays_ch9[4] = {36, 47, 57, 0};
|
int16_t pdoa_delays_ch5[4] = {51, -73, -57, 0};
|
int16_t pdoa_delays_ch2[4] = {36, 47, 57, 0};
|
|
int16_t pdoa_gains_ch9[4] = {108, 99, 98, 100};
|
int16_t pdoa_gains_ch5[4] = {94, 103, 87, 100};
|
int16_t pdoa_gains_ch2[4] = {108, 99, 98, 100};
|
|
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
|
|
#if 0
|
// 3-ANTs: 3, 0, 1
|
int16_t pdoa_delays_ch9[4] = {0, 36, 47};
|
int16_t pdoa_delays_ch5[4] = {0, 51, -73};
|
int16_t pdoa_delays_ch2[4] = {0, 36, 47};
|
|
int16_t pdoa_gains_ch9[4] = {100, 108, 99};
|
int16_t pdoa_gains_ch5[4] = {100, 94, 103};
|
int16_t pdoa_gains_ch2[4] = {100, 108, 99};
|
#else
|
// 3-ANTs: 1, 2, 3
|
int16_t pdoa_delays_ch9[4] = {47, 57, 0};
|
int16_t pdoa_delays_ch5[4] = {-73, -57, 0};
|
int16_t pdoa_delays_ch2[4] = {47, 57, 0};
|
|
int16_t pdoa_gains_ch9[4] = {99, 98, 100};
|
int16_t pdoa_gains_ch5[4] = {103, 87, 100};
|
int16_t pdoa_gains_ch2[4] = {99, 98, 100};
|
#endif
|
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
|
// 2-ANTs: 2, 3
|
int16_t pdoa_delays_ch9[4] = {57, 0};
|
int16_t pdoa_delays_ch5[4] = {-57, 0};
|
int16_t pdoa_delays_ch2[4] = {57, 0};
|
|
int16_t pdoa_gains_ch9[4] = {98, 100};
|
int16_t pdoa_gains_ch5[4] = {87, 100};
|
int16_t pdoa_gains_ch2[4] = {98, 100};
|
#else
|
// 2-ANTs: 3, 0
|
int16_t pdoa_delays_ch9[4] = {0, 36};
|
int16_t pdoa_delays_ch5[4] = {0, 51};
|
int16_t pdoa_delays_ch2[4] = {0, 36};
|
|
int16_t pdoa_gains_ch9[4] = {100, 108};
|
int16_t pdoa_gains_ch5[4] = {100, 94};
|
int16_t pdoa_gains_ch2[4] = {100, 108};
|
#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
|
|
memcpy((uint8_t *)&board_param.ant_delays[CALIB_CH9], ant_delays_ch9, sizeof(ant_delays_ch9));
|
memcpy((uint8_t *)&board_param.ant_delays[CALIB_CH5], ant_delays_ch5, sizeof(ant_delays_ch5));
|
memcpy((uint8_t *)&board_param.ant_delays[CALIB_CH2], ant_delays_ch2, sizeof(ant_delays_ch2));
|
|
#if RX_ANT_PORTS_NUM > 1
|
memcpy((uint8_t *)&board_param.pdoa_delays[CALIB_CH9], pdoa_delays_ch9, sizeof(pdoa_delays_ch9));
|
memcpy((uint8_t *)&board_param.pdoa_delays[CALIB_CH5], pdoa_delays_ch5, sizeof(pdoa_delays_ch5));
|
memcpy((uint8_t *)&board_param.pdoa_delays[CALIB_CH2], pdoa_delays_ch2, sizeof(pdoa_delays_ch2));
|
|
memcpy((uint8_t *)&board_param.pdoa_gains[CALIB_CH9], pdoa_gains_ch9, sizeof(pdoa_gains_ch9));
|
memcpy((uint8_t *)&board_param.pdoa_gains[CALIB_CH5], pdoa_gains_ch5, sizeof(pdoa_gains_ch5));
|
memcpy((uint8_t *)&board_param.pdoa_gains[CALIB_CH2], pdoa_gains_ch2, sizeof(pdoa_gains_ch2));
|
|
memcpy((uint8_t *)&board_param.pdoa_offsets[0], pdoa_offsets, sizeof(pdoa_offsets));
|
#endif
|
|
board_param.dev_role = 0;
|
board_param.dev_role_idx = 0;
|
#endif
|
}
|
|
void board_calibration_params_load(void)
|
{
|
board_calibration_params_default();
|
#ifdef WSF_EN
|
if (TRUE == WsfNvmReadData(BOARD_X38M4_LOAD_CAP, &board_param.x38m4_load_cap, sizeof(board_param.x38m4_load_cap), 0))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
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))
|
{
|
board_param.flag |= (1 << BOARD_X32K_LOAD_CAP);
|
}
|
|
if (TRUE == WsfNvmReadData(BOARD_CALIB_X38M4_TEMPERATURE, (uint8_t *)&board_param.calib_x38m4_temperature, sizeof(board_param.calib_x38m4_temperature), 0))
|
{
|
board_param.flag |= (1 << BOARD_CALIB_X38M4_TEMPERATURE);
|
}
|
|
if (TRUE == WsfNvmReadData(BOARD_CALIB_X38M4_PPM, (uint8_t *)&board_param.calib_x38m4_ppm, sizeof(board_param.calib_x38m4_ppm), 0))
|
{
|
board_param.flag |= (1 << BOARD_CALIB_X38M4_PPM);
|
}
|
|
if (TRUE == WsfNvmReadData(BOARD_ANGLE_CORRECTION, (uint8_t *)&board_param.angle_correction, sizeof(board_param.angle_correction), 0))
|
{
|
board_param.flag |= (1 << BOARD_ANGLE_CORRECTION);
|
}
|
#endif
|
}
|
|
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_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))) ||
|
((id == BOARD_PEER_SHORT_ADDR) && (param_len == sizeof(board_param.peer_short_addr))) ||
|
((id == BOARD_ANT_DELAYS) && (param_len == sizeof(board_param.ant_delays))) ||
|
((id == BOARD_PDOA_DELAYS) && (param_len == sizeof(board_param.pdoa_delays))) ||
|
((id == BOARD_PDOA_GAINS) && (param_len == sizeof(board_param.pdoa_gains))) ||
|
((id == BOARD_PDOA_ANT_SPACE) && (param_len == sizeof(board_param.pdoa_ant_space))) ||
|
((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_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))))
|
{
|
ret = WsfNvmWriteData(id, param, param_len, 0);
|
}
|
#endif
|
return ret;
|
}
|
|
void board_ranging_result_correct(uint16_t *distance, int16_t *azimuth, int16_t *elevation)
|
{
|
if ((distance == NULL) || (azimuth == NULL) || (elevation == NULL))
|
{
|
return;
|
}
|
#ifdef UWB_EN
|
#if (ANT_PATTERN == ANT_PATTERN_SQUARE) // 3D
|
|
#elif (ANT_PATTERN == ANT_PATTERN_TRIANGLE_REGULAR) // 3D
|
|
#elif (ANT_PATTERN == ANT_PATTERN_LINEAR) // 2D -90 ~ 90
|
// azimuth correction
|
float post_azimuth = mk_q7_to_f32(*azimuth);
|
|
if (board_param.angle_correction[0])
|
{
|
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);
|
}
|
|
post_azimuth = ((post_azimuth > 90) ? 90 : ((post_azimuth < -90) ? -90 : post_azimuth));
|
*azimuth = mk_f32_to_q7(post_azimuth);
|
#endif
|
#endif
|
}
|
|
#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_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);
|
}
|
|
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);
|
}
|
|
void board_led_on(enum IO_PIN_T idx)
|
{
|
gpio_pin_set(idx);
|
}
|
|
void board_led_off(enum IO_PIN_T idx)
|
{
|
gpio_pin_clr(idx);
|
}
|
|
void board_led_toggle(enum IO_PIN_T idx)
|
{
|
gpio_pin_toggle(idx);
|
}
|
|
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)
|
{
|
#if !defined(CELL_PHONE_EN)
|
board_led_off(BOARD_LED_1);
|
#endif
|
}
|
|
void board_restore_from_power_down(void)
|
{
|
#if defined(UCI_INTF_PORT)
|
uci_tl_resume();
|
#else
|
// button - restore interrupt type
|
if (button_irq_handler)
|
{
|
gpio_enable_irq(BOARD_SW_1, GPIO_IRQ_TYPE_FALLING_EDGE, button_irq_handler);
|
}
|
#endif
|
|
#if !defined(CELL_PHONE_EN)
|
board_led_on(BOARD_LED_1);
|
#endif
|
|
// system timer
|
sys_timer_open();
|
|
#if TRACE_EN
|
trace_open(user_trace_port, TRACE_BAUD_RATE);
|
#endif
|
}
|