ZHCAEI9 September   2024 MSPM0L1227 , MSPM0L1227-Q1 , MSPM0L1228 , MSPM0L1228-Q1 , MSPM0L2227 , MSPM0L2227-Q1 , MSPM0L2228 , MSPM0L2228-Q1

 

  1.   1
  2.   摘要
  3.   商标
  4. 1引言
  5. 2低频子系统简介
    1. 2.1 使用 VBAT 对 LFSS IP 进行复位
    2. 2.2 电源域电源检测
      1. 2.2.1 启动序列
      2. 2.2.2 LFSS IP 行为
    3. 2.3 LFXT、LFOSC
    4. 2.4 独立看门狗计时器 (IWDT)
    5. 2.5 防篡改 I/O
      1. 2.5.1 IOMUX 模式
      2. 2.5.2 防篡改模式
        1. 2.5.2.1 篡改事件检测
        2. 2.5.2.2 时间戳事件输出
        3. 2.5.2.3 检测信号发生器
    6. 2.6 便笺式存储器 (SPM)
    7. 2.7 实时时钟 (RTC)
    8. 2.8 VBAT 充电模式
  6. 3应用示例
    1. 3.1 防篡改 I/O 检测信号示例
    2. 3.2 RTC 防篡改 I/O 时间戳事件示例
    3. 3.3 超级电容器充电示例
    4. 3.4 LFOSC 转换回 LFXT 的示例
    5. 3.5 RTC_A 校准
      1. 3.5.1 外设 ADC 12
      2. 3.5.2 RTC_A

RTC_A

使用 RT0PS 的 Q0 输出对 RTC 进行校准需要超过 60 秒的时间。通过每四分之一秒增加或减去 1 个时钟脉冲,可以近似得出 ±1ppm 的校正值。一个校准周期内最大可调节范围为 ±240ppm。每个周期都包含对偏移误差和温度误差的调整。超过 ±240ppm 界限的调整会达到饱和状态,但可以在多个周期内完成总补偿。如果未启用 RTC,校准将被禁用。

有 CAL 和 TCMP 两个寄存器用于校准。偏移调整值写入 CAL 寄存器,温度写入 TCMP。但是,TCMP 寄存器会存储两种误差类型之间的净补偿值。当设置 CAL 寄存器时,温度调整值复位为 0,并且 TCMP 仅存储偏移调整值。

进行校准以调整偏移误差时,RTC 提供一系列频率输出以用于外部测量。测试频率为 LFCLK (32kHz)、512Hz、256Hz 和 1Hz。选择结果存储在 CAL 寄存器的 RTCOCALFX 位字段中,如果设置为 0,则会禁用偏移校准。可以使用方程式 6 来计算偏移误差。

方程式 6. 60×16384×1-fRTCCLK32768

其中

  • 60 是校准周期长度(以秒为单位)
  • 16384 是 RT0PS 的 Q0 输出频率
  • fRTCCLK 是测得的输出频率乘以时钟分频因子
  • 32768 是期望的 LFCLK 频率

计算出误差后,可以写入符号和幅度位字段。符号指示是向上还是向下调整。如果误差为正(向上校准),则设置 RTCOCALS,如果符号为负(向下校准),则清除 RTCOCALS。RTCOCALX 是幅度,限制为最大 240ppm。如果将有符号结果写入 RTCOCALX,负值用二进制补码表示,并饱和至 240ppm。

温度漂移校准方法是获取 ADC 的温度近似值,计算由相对于晶体周转温度的偏差引起的频率误差,然后将结果写入 TCMP 寄存器。获取温度近似值的过程如节 3.5.1所述。使用方程式 7 可计算频率误差。

方程式 7. T C O M P = T A P P R O X - T i × B

其中

  • TCOMP 是温度补偿值
  • TAPPROX 是测量的温度近似值
  • Ti 是晶体振荡器周转温度
  • B 是晶体振荡器抛物线系数

前面的信息可以在晶体振荡器数据表中找到。

该公式会根据时钟信号的来源而变化。具体而言,周转温度和抛物线系数变量取决于所使用的振荡器类型。此示例中使用的是音叉外部晶体,周转温度和抛物线系数见数据表。音叉晶体的一个独特属性就是温度偏差会导致负频率偏差。这意味着补偿方向是向上。计算出误差后,与偏移误差类似,符号(向上)将写入 RTCTCMPS 位字段,而幅度将写入 RTCTCMPX 位字段。写入成功后,当读取 TCMP 寄存器时,该寄存器已存储偏移误差和温度偏差之间的净补偿值。如果净补偿值太大,RTCTCMPX 将饱和至 240ppm。由温度偏差确定的补偿将在下一个校准周期引入,而不是在当前校准周期引入。由于每个周期的长度为 60 秒,此示例每分钟只测量一次温度,并由 RTC_A 间隔中断进行触发。可以更改该值来多次测量温度并取平均值­。

#include "ti_msp_dl_config.h"

/*
 * The following trim parameter is provided in the device datasheet in chapter
 * "Temperature Sensor"
 */
#define TEMP_TS_TRIM_C                                            ((uint32_t)30)

/*
 * Constant below is (1/TSc). Where TSc is Temperature Sensor coefficient
 * available in the device datasheet
 */
#define TEMP_TS_COEF_mV_C                                             (-555.55f)

#define ADC_VREF_VOLTAGE                                                  (1.4f)
#define ADC_BIT_RESOLUTION                                   ((uint32_t)(1)<<12)

/*
 * The following turnover and  Parabolic Coefficient parameter is provided 
 * in the crystal oscillator datasheet
 */
#define TEMP_CRYSTAL_Ti_C                                         ((uint32_t)25)
#define TEMP_CRYSTAL_B_PPM_C2                                            (-0.04f)

/* Offset measurements */
typedef struct measFreq {
    double freq;
    DL_RTC_COMMON_OFFSET_CALIBRATION_SIGN sign;
} measFreq;

volatile bool gStatus = false;
volatile bool gCheckADC;

void offset_error_correction(void) {
    measFreq slowCrystal;
    measFreq fastCrystal;

    /* Simulated frequency measurements (will need to be manually measured)*/
    slowCrystal.freq = 511.9658;
    fastCrystal.freq = 512.0241;

    /* Correction sign is adjusted up for slow measured frequencies and down for fast measured frequencies */
    slowCrystal.sign = DL_RTC_COMMON_OFFSET_CALIBRATION_SIGN_UP;
    fastCrystal.sign = DL_RTC_COMMON_OFFSET_CALIBRATION_SIGN_DOWN;

    measFreq examples[2] = {slowCrystal, fastCrystal};

    /* Process for updating calibration register (for both slow and fast measurements)*/
    for(uint8_t i = 0; i < 2; i++) {
        /* Division Factor for 512Hz output frequency */
        uint8_t divFact = 64;

        /* Ideal Crystal Oscillation frequency*/
        uint16_t optOsc = 32768;

        /* Error Correction Formula:
         * Frtcclk = Frtcclk,meas * divider factor
         * Offset Value = Round(60 * 16384 * (1 - Frtcclk/32768))
         */
         
        double Frtcclk = examples[i].freq * divFact;
        uint8_t offVal = fabs(round(60 * 16384 * (1 - (Frtcclk / optOsc))));

        /* Wait until RTC is ready for compensation */
        while (!DL_RTC_A_isReadyToCalibrate(RTC_A)) {
            ;
        }

        /* Sets the offset error calibration adjustment value */
        DL_RTC_A_setOffsetCalibrationAdjValue(RTC_A, examples[i].sign, offVal);

        /* Check if write was successful */
        gStatus = DL_RTC_A_isCalibrationWriteResultOK(RTC_A);

        /* Stop the debugger to examine the output. At this point,
         * gStatus should be equal to "true" and the CAL register
         * should be updated.
         * slow crystal adjustment should be +66ppm
         * fast crystal adjustment should be -46ppm    
         */
        __BKPT(0);
    }
}

void temp_drift_correction(float vTrim) {
    uint32_t adcResult, tComp;
    float vSample, tSample;    
    DL_RTC_COMMON_TEMP_CALIBRATION tSign;

    gCheckADC = false;   

    /* Read stored ADC value */
    adcResult = DL_ADC12_getMemResult(ADC12_0_INST, ADC12_0_ADCMEM_0);

    /*
    * Convert ADC result to equivalent voltage:
    * Vsample = (VREF_VOLTAGE_MV*(adcResult -0.5))/(2^ADC_BIT_RESOLUTION)
    */
    vSample = ADC_VREF_VOLTAGE / ADC_BIT_RESOLUTION * (adcResult -0.5);

    /*
    * Apply temperature sensor calibration data
    * TSAMPLE = (TEMP_TS_COEF_mV_C) * (vSample - vTrim) + TEMP_TS_TRIM_C
    */ 
    tSample = TEMP_TS_COEF_mV_C * (vSample - vTrim) + TEMP_TS_TRIM_C;

    /*
     * Compensation sign and value
     * TCOMP = (tSample - TEMP_CRYSTAL_Ti_C)^2 * TEMP_CRYSTAL_B_PPM_C2
     */
    tSign = RTC_TCMP_RTCTCMPS_UP;
    tComp = fabs(pow((int16_t)tSample - (int16_t)TEMP_CRYSTAL_Ti_C, 2) * TEMP_CRYSTAL_B_PPM_C2);

    /* Wait until RTC is ready for compensation */
    while (!DL_RTC_A_isReadyToCalibrate(RTC_A)) {
        ;
    }

    /* Sets the temperature error calibration value */
    DL_RTC_Common_setTemperatureCompensation(RTC_A, tSign, tComp);

    /* Check if write was successful */
    gStatus = DL_RTC_A_isCalibrationWriteResultOK(RTC_A);

    /* Stop the debugger to examine the output. At this point,
        * gStatus should be equal to "true" and the TCMP register
        * should be updated.
        * The TCMP register will show the net error
        * of the offset and temperature errors.    
        */
    __BKPT(0);
}

int main(void)
{
    /* Output frequency for offset calculation initialized to 512Hz */
    SYSCFG_DL_init();

    /* Enable RTC interrupts on device */
    NVIC_EnableIRQ(RTC_A_INST_INT_IRQN);

    /* Start RTC clock */
    DL_RTC_A_enableClockControl(RTC_A);

    /* Disclaimers:
     * Writing to the RTCOCAL register resets the temperature
     * to zero.
     *
     * The maximum correction in one calibration cycle is +-240ppm.
     * Any error outside this range will be ignored.
     */

    /* Offset Error Correction Mechanism */
    offset_error_correction();

    /* Temperature Drift Correction Mechanism */

    /*
     * Convert TEMP_SENSE0 result to equivalent voltage:
     * Vtrim = (ADC_VREF_VOLTAGE*(TEMP_SENSE0 -0.5))/(2^12)
     */
    float vTrim;
    vTrim = ADC_VREF_VOLTAGE / ADC_BIT_RESOLUTION * (DL_SYSCTL_getTempCalibrationConstant() -0.5);

    gCheckADC = false;
    while (1) {
        if(gCheckADC) {
            temp_drift_correction(vTrim);
        }
        DL_ADC12_startConversion(ADC12_0_INST);
        __WFI();
        DL_ADC12_stopConversion(ADC12_0_INST);
    }
}

void RTC_A_INST_IRQHandler(void)
{
    switch (DL_RTC_A_getPendingInterrupt(RTC_A)) {
        case DL_RTC_A_IIDX_INTERVAL_TIMER:
            gCheckADC = true;
            break;
        default:
            break;
    }
}