/*! \file gd32h75e_lpdts.c \brief LPDTS driver \version 2025-08-07, V1.2.0, firmware for GD32H75E */ /* Copyright (c) 2025, GigaDevice Semiconductor Inc. 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 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 the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 "gd32h75e_lpdts.h" /* LPDTS high threshold value offset macro */ #define LPDTS_IT_INTHT_OFFSET ((uint32_t)16U) /* sampling time offset macro */ #define LPDTS_CFG_SPT_OFFSET ((uint32_t)16U) /* engineering value offset macro */ #define LPDTS_SDATA_VAL_OFFSET ((uint32_t)16U) /* the T0 temperature macro */ #define LPDTS_T0_TMP_VAL ((uint32_t)25U) /*! \brief reset the LPDTS registers \param[in] none \param[out] none \retval none */ void lpdts_deinit(void) { rcu_periph_reset_enable(RCU_LPDTSRST); rcu_periph_reset_disable(RCU_LPDTSRST); } /*! \brief initialize the parameters of LPDTS struct with the default values \param[in] none \param[out] init_struct: the initialization data needed to initialize LPDTS \retval none */ void lpdts_struct_para_init(lpdts_parameter_struct *init_struct) { /* set the struct with the default values */ init_struct->ref_clock = REF_PCLK; init_struct->trigger_input = NO_HARDWARE_TRIGGER; init_struct->sampling_time = SPT_CLOCK_15; } /*! \brief initialize the LPDTS \param[in] init_struct: the initialization data needed to initialize LPDTS_CFG ref_clock: REF_PCLK, REF_LXTAL trigger_input: NO_HARDWARE_TRIGGER, LPDTS_TRG sampling_time: SPT_CLOCK_x(x=1..15) \param[out] none \retval none */ void lpdts_init(lpdts_parameter_struct *init_struct) { #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_INITIALIZATION_DATA(init_struct)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0003U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { uint32_t reg; /* configure the LPDTS_CFG */ reg = LPDTS_CFG; reg &= ~(LPDTS_CFG_REFSEL | LPDTS_CFG_ITSEL | LPDTS_CFG_SPT); reg |= (init_struct->ref_clock | init_struct->trigger_input | init_struct->sampling_time); LPDTS_CFG = reg; } } /*! \brief enable LPDTS temperature sensor \param[in] none \param[out] none \retval none */ void lpdts_enable(void) { LPDTS_CFG |= LPDTS_CFG_TSEN; } /*! \brief disable LPDTS temperature sensor \param[in] none \param[out] none \retval none */ void lpdts_disable(void) { LPDTS_CFG &= ~LPDTS_CFG_TSEN; } /*! \brief enable LPDTS software trigger \param[in] none \param[out] none \retval none */ void lpdts_soft_trigger_enable(void) { LPDTS_CFG |= LPDTS_CFG_TRGS; } /*! \brief disable LPDTS software trigger \param[in] none \param[out] none \retval none */ void lpdts_soft_trigger_disable(void) { LPDTS_CFG &= ~LPDTS_CFG_TRGS; } /*! \brief configure LPDTS high threshold value \param[in] value: high threshold value(0~65535) \param[out] none \retval none */ void lpdts_high_threshold_set(int32_t value) { #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_HIGH_THRESHOLD(value)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0008U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { uint32_t reg; /* configure the LPDTS_IT */ reg = LPDTS_IT; reg &= ~LPDTS_IT_INTHT; reg |= (uint32_t)value << LPDTS_IT_INTHT_OFFSET; LPDTS_IT = reg; } } /*! \brief configure LPDTS low threshold value \param[in] value: low threshold value(0~65535) \param[out] none \retval none */ void lpdts_low_threshold_set(int32_t value) { #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_LOW_THRESHOLD(value)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0009U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { uint32_t reg; /* configure the LPDTS_IT */ reg = LPDTS_IT; reg &= ~LPDTS_IT_INTLT; reg |= (uint32_t)value; LPDTS_IT = reg; } } /*! \brief configure LPDTS reference clock selection \param[in] source: reference clock source only one parameter can be selected which is shown as below: \arg REF_PCLK: high speed reference clock (PCLK) \arg REF_LXTAL: low speed reference clock (LXTAL) \param[out] none \retval none */ void lpdts_ref_clock_source_config(uint32_t source) { #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_REF_CLOCK_SOURCE(source)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0010U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { uint32_t reg; /* configure the LPDTS_CFG */ reg = LPDTS_CFG; reg &= ~LPDTS_CFG_REFSEL; reg |= source; LPDTS_CFG = reg; } } /*! \brief get temperature from LPDTS \param[in] none \param[out] none \retval temperature: temperature in deg C */ int32_t lpdts_temperature_get(void) { uint32_t freq; uint32_t count; uint32_t t0; uint32_t t0_freq; uint32_t ramp_coeff; uint32_t reg_cfg; int32_t temperature; /* get the total number of samples */ count = (LPDTS_DATA & LPDTS_DATA_COVAL); /* get LPDTS_CFG configuration */ reg_cfg = LPDTS_CFG; /* get the module frequency on Hz */ if((reg_cfg & LPDTS_CFG_REFSEL) == LPDTS_CFG_REFSEL) { freq = (LXTAL_VALUE * count) / (2U * ((reg_cfg & LPDTS_CFG_SPT) >> LPDTS_CFG_SPT_OFFSET)); } else { freq = (2U * rcu_clock_freq_get(CK_APB1) / count) * ((reg_cfg & LPDTS_CFG_SPT) >> LPDTS_CFG_SPT_OFFSET); } /* read factory settings */ t0 = (LPDTS_SDATA & LPDTS_SDATA_VAL) >> LPDTS_SDATA_VAL_OFFSET; if(t0 == 0U) { t0 = LPDTS_T0_TMP_VAL; } /* get the T0 frequency on Hz */ t0_freq = (LPDTS_SDATA & LPDTS_SDATA_FREQ) * 100U; /* get the ramp coefficient for the temperature sensor on deg C/Hz */ ramp_coeff = LPDTS_RDATA & LPDTS_RDATA_RCVAL; /* figure out the temperature deg C */ temperature = (int32_t)t0 + (((int32_t)freq - (int32_t)t0_freq) / (int32_t)ramp_coeff); return temperature; } /*! \brief get LPDTS flag \param[in] flag: LPDTS ready flag only one parameter can be selected which is shown as below: \arg LPDTS_FLAG_TSR \param[out] none \retval FlagStatus: SET or RESET */ FlagStatus lpdts_flag_get(uint32_t flag) { FlagStatus status = RESET; #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_FLAG(flag)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0012U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { if(LPDTS_STAT & flag) { status = SET; } } /* return the state of corresponding LPDTS flag */ return status; } /*! \brief enable LPDTS interrupt \param[in] interrupt: the LPDTS interrupt one or more parameters can be selected which is shown as below: \arg LPDTS_INT_EM \arg LPDTS_INT_LT \arg LPDTS_INT_HT \arg LPDTS_INT_EMA \arg LPDTS_INT_LTA \arg LPDTS_INT_HTA \param[out] none \retval none */ void lpdts_interrupt_enable(uint32_t interrupt) { #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_INTERRUPT(interrupt)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0013U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { LPDTS_INTEN |= interrupt; } } /*! \brief disable LPDTS interrupt \param[in] interrupt: the LPDTS interrupt one or more parameters can be selected which is shown as below: \arg LPDTS_INT_EM \arg LPDTS_INT_LT \arg LPDTS_INT_HT \arg LPDTS_INT_EMA \arg LPDTS_INT_LTA \arg LPDTS_INT_HTA \param[out] none \retval none */ void lpdts_interrupt_disable(uint32_t interrupt) { #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_INTERRUPT(interrupt)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0014U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { LPDTS_INTEN &= ~interrupt; } } /*! \brief get LPDTS interrupt flag \param[in] flag: LPDTS interrupt flag only one parameter can be selected which is shown as below: \arg LPDTS_INT_FLAG_EM \arg LPDTS_INT_FLAG_LT \arg LPDTS_INT_FLAG_HT \arg LPDTS_INT_FLAG_EMA \arg LPDTS_INT_FLAG_LTA \arg LPDTS_INT_FLAG_HTA \param[out] none \retval FlagStatus: SET or RESET */ FlagStatus lpdts_interrupt_flag_get(uint32_t flag) { FlagStatus status = RESET; uint32_t state; #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_INTERRUPT_FLAG(flag)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0015U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { state = LPDTS_STAT; if(state & flag) { state = LPDTS_INTEN; if(state & flag) { status = SET; } } } /* return the state of corresponding LPDTS flag */ return status; } /*! \brief clear the LPDTS interrupt flag \param[in] flag: LPDTS flag one or more parameter can be selected which is shown as below: \arg LPDTS_INT_FLAG_EM \arg LPDTS_INT_FLAG_LT \arg LPDTS_INT_FLAG_HT \arg LPDTS_INT_FLAG_EMA \arg LPDTS_INT_FLAG_LTA \arg LPDTS_INT_FLAG_HTA \param[out] none \retval none */ void lpdts_interrupt_flag_clear(uint32_t flag) { #ifdef FW_DEBUG_ERR_REPORT if(NOT_LPDTS_INTERRUPT_FLAG(flag)) { fw_debug_report_err(LPDTS_MODULE_ID, API_ID(0x0016U), ERR_PARAM_INVALID); } else /* FW_DEBUG_ERR_REPORT */ #endif { /* clear the flags */ LPDTS_INTC = flag; } }