电表在不同供电模式下的安全过渡

电源设计应用

435人已加入

描述

摘要:本文介绍了两个固件,用作Teridian™ 71M6521电表IC的演示程序,版本号为4.8p。这些固件有助于改善71M6521在功率模式之间转换时的可靠性,并在器件恢复工作模式后提供适当的实时时钟(RTC)修正。文章讨论了程序修改及设计细节,便于用户对现有固件进行必要的更新。 
 

概述

微调“保险丝”

微调“保险丝”实际上指的是一组非易失(NV)存储器,在Maxim的Teridian电表IC生产过程中用于调整IC的模拟和数字特征参数。器件出厂后,微调“保险丝”内存储的内容不再改变,用于后续产品中的参数补偿,例如,用来微调VREF电压,使其稳定在1.195 VDC ,误差不超过±1mV;还可用于调整VBIAS内部电压,使其稳定在目标值。

IC工作期间,按照固定的时间间隔读取微调“保险丝”的数值,由IC内部的硬件电路进行适当的参数调整。从“保险丝”读取的数据送入硬件控制电路和位于I/O RAM的保险丝寄存器(图1)。71M6521系列产品中共包含7个独立的微调“保险丝”数值,向I/O RAM寄存器0x20FD (TRIMSEL)写入1-7之间的任何数值,可从I/O RAM寄存器0x20FF (TRIM)中读取相应的“保险丝”数据。

电表
图1. 微调保险丝工作原理

错误读取微调“保险丝”

71M6521 IC支持三种低功耗模式(休眠模式、LCD单独有效模式以及关断模式)。低功耗模式下,无法支持IC正常工作的电流消耗。

在极端的电磁干扰(EMI)环境下,或者是当电源超乎寻常地反复断电的情况下,可能会影响到“保险丝”数据的读取和参数调整,错误地读取到某个“保险丝”数据。发生这种情况时,可能导致几种错误结果。当电源发生高速“振荡”,使得71M6521在工作模式与关断模式之间反复切换时,将会提高器件故障的概率,当交流电缓慢爬升、下降,而后续使用的是“软”电源时,很容易发生这种状况。电源振荡导致71M6521在正常供电(正常工作模式)和低功耗(关断)模式之间频繁切换,由于“保险丝”读取错误导致器件故障的可能性非常小,只有当电表在长达若干天,甚至几个星期的时间内频繁断电时,才有可能看到故障状况。

“保险丝”读取错误导致IC工作故障可能有几种不同的表现形式,具体取决于错误读取的“保险丝”数据。故障现象可能是以下几种情况之一:

MPU软件运行在未知状态,但依据固件的不同,有些情况下可能终止内部时钟,使看门狗定时器无法复位电表。

产生未知的内部电源电压和检测门限,这种情况下可能导致外部电源作用到V1引脚,在唤醒时钟尚未建立的前提下进入休眠模式。有些情况下,不恰当地初始化内部电源达到一个超时限制时,可能导致RTC计时错误。

在电表中从根本上消除EMI可能不太现实,但是,在器件进入关断模式时通过测试IC的微调“保险丝”,固件可以检测并避免发生上述故障。

新版本演示程序解决的另一问题是RTC时间偏移的修正。早期软件中所包含的RTC程序集成了长期抖动导致RTC偏差的修正,复位后进行调整。

改进程序的应用示例

本应用笔记介绍的程序支持所有版本的71M6521,包括71M6521BE、71M6521DE和71M6521FE。Maxim推荐在带有备份电池的新设计中采用固件修正。

功率模式切换期间可能产生的失效

71M6521中的微调“保险丝”由控制逻辑保证,重复上电或极端EMI可能影响微调“保险丝”的数据读取。失效原因包括:

电表频繁断电或出现极端EMI。

电表从工作状态进入关断模式,新的锂电池供电的情况下,错误地读取微调“保险丝”的数据。电池电压(典型值为3.6 VDC)与71M6521正常工作时的电压(典型值为3.3 VDC)不同,导致失效。

配备电池的电表似乎更容易受到影响,因为不带电池的电表在主电源断电并再次上电后,能够经历一次干净的复位(POR)过程。

在供电模式转换期间,可能引发上文提及的失效现象,但很难准确定位具体故障,因为这取决于诸多因素:断电或EMI、电表固件、电池选择、电源设计等,这些都会影响到微调“保险丝”的读取错误。大多数电表即使在极端测试条件下,也不会发生故障。

当电表返回正常工作模式时,电源能够支持更大的工作电流,即可提供微调自校准数据。但可能需要重新恢复电表的工作状态。

RTC失效事件

RTC程序用于补偿电表在低功耗模式下产生的时间偏差,但并非在启动时同步调整,而会累计抖动产生的漂移。

4.8p演示程序

程序测试

实际测试时为演示板配备了新电池,配置显示默认值(显示RTC的时钟)。然后,在8周内每隔10秒重复一次交流电的断电/上电。简单地把电源稳定在标称交流电压,然后开始测试。好的设计应该能够正确地恢复系统工作,合理显示时间信息。程序经过8周测试后没有出现失效。

软件的影响

4.8p演示程序能够在运行main()之前出发PLL_OK中断,保证在固件初始化期间能够检测到掉电故障并进行相应的处理。必须谨慎管理其它中断操作,以避免出现严重的故障现象。

任何情况下,4.8p演示软件都可以在唤醒定时器中保持一个非零数值。正常工作时,唤醒定时器不会计数或触发唤醒过程,除非IC意外进入休眠或仅显示LCD模式。发生这种事件时,将触发唤醒定时器工作,唤醒电表并从故障状态下恢复电表工作。

程序存储位置

目标代码应该把修正程序放置在闪存的前8KB。Keil® IDE中,可以在项目平台更改目标程序,选择<点击鼠标右键>optionsBL_51 Locate TabCode Space。演示程序中,该指令置于存储器尽可能低的位置:

?C_C51STARTUP,?PR?_?PLL_ISR?BATMODES_20,?PR?_?BATMODE_CHANGE?BATMODES_20,

?C_C51STARTUP包含演示程序的启动代码。

?PR?_?PLL_ISR?BATMODES_20SAFE,?PR?_?BATMODE_CHANGE?BATMODES_20SAFE执行PLL_OK中断例程时需要。

PLL_OK中断

以下程序应该置于PLL_OK中断例程,检测到关断模式时运行。4.8p mainatmodes_20.c中给出了经过测试的程序代码。

 

    extern void trim_test(void) small reentrant;

    EA = 0;
    CONFIG0 = 0;        // Make sure we are running as fast as we can.
    IFLAGS = (~IE_PLLFALL_) & (~IE_PLLRISE_);  // force an edge to occur

    WAKE = 0x81;        // force a wake timer wake if sleep is forced

    trim_test();        // From start-up code.

 

启动程序

以下启动程序用来替代startup.a51,Maxim提供经过测试的软件代码(4.8p演示软件中,启动程序位于utilstartup_n_safe.a51),以下列出了程序代码。

第一次在工厂运行程序时,微调寄存器的内容被复制到闪存内。之后,对微调寄存器进行测试。一旦测试中发生失效,程序将简单地把IC置于休眠模式,然后重新读取微调数据。唤醒器件操作后,IC会自动读取微调“保险丝”内的数值。复位期间调用保险丝测试程序,将重新读取微调“保险丝”的数据并进行修正。

 

;/***************************************************************************
; * This code and information is provided "as is" without warranty of any   *
; * kind, either expressed or implied, including but not limited to the     *
; * implied warranties of merchantability and/or fitness for a particular   *
; * purpose.                                                                *
; *                                                                         *
; * Copyright (C) 2011 Maxim Integrated Products, Inc. All Rights Reserved. *
; ***************************************************************************/
;//**************************************************************************
;//    
;//  DESCRIPTION: 71M652x POWER METER - STARTUP Code.
;//
;//**************************************************************************
;//               
;// File: STARTUP_N_SAFE.A51.
;//               
$NOMOD51
;------------------------------------------------------------------------------
;  This file is part of the C51 Compiler package
;  Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
;------------------------------------------------------------------------------
;  STARTUP.A51:  This code is executed after processor reset.
;
;  To translate this file use A51 with the following invocation:
;
;     A51 STARTUP_N_SAFE.A51
;
;  To link the modified STARTUP_N_SAFE.OBJ file to your application use the following
;  BL51 invocation:
;
;     BL51 , STARTUP_N_SAFE.OBJ 
;
;------------------------------------------------------------------------------
;
;  User-defined Power-On Initialization of Memory
;  With the following EQU statements the initialization of memory
;  at processor reset can be defined:
;
;               ; the absolute start-address of IDATA memory is always 0
IDATALEN        EQU     100H    ; the length of IDATA memory in bytes.
;
XDATASTART      EQU     0H      ; the absolute start-address of XDATA memory
XDATALEN        EQU     000H    ; the length of XDATA memory in bytes.
;
PDATASTART      EQU     0H      ; the absolute start-address of PDATA memory
PDATALEN        EQU     0H      ; the length of PDATA memory in bytes.
;
;  Notes:  The IDATA space overlaps physically the DATA and BIT areas of the
;          8051 CPU. At minimum the memory space occupied from the C51 
;          run-time routines must be set to zero.
;------------------------------------------------------------------------------
;
;  Reentrant Stack Initialization
;
;  The following EQU statements define the stack pointer for reentrant
;  functions and initialized it:
;
;  Stack Space for reentrant functions in the SMALL model.
IBPSTACK        EQU     1       ; set to 1 if small reentrant is used.
IBPSTACKTOP     EQU     0FFH+1  ; set top of stack to highest location+1.
;
;  Stack Space for reentrant functions in the LARGE model.      
XBPSTACK        EQU     0       ; set to 1 if large reentrant is used.
XBPSTACKTOP     EQU     07FFH+1; set top of stack to highest location+1.
;
;  Stack Space for reentrant functions in the COMPACT model.    
PBPSTACK        EQU     0       ; set to 1 if compact reentrant is used.
PBPSTACKTOP     EQU     07FFH+1; set top of stack to highest location+1.
;
;------------------------------------------------------------------------------
;  Page Definition for Using the Compact Model with 64 KByte xdata RAM
;
;  The following EQU statements define the xdata page used for pdata
;  variables. The EQU PPAGE must conform with the PPAGE control used
;  in the linker invocation.
;
PPAGEENABLE     EQU     1       ; set to 1 if pdata object are used.
;
PPAGE           EQU     7       ; define PPAGE number.
                PUBLIC  PPAGE_SFR
PPAGE_SFR       DATA    0BFH    ; SFR that supplies uppermost address byte
;               (most 8051 variants use P2 as uppermost address byte)
;------------------------------------------------------------------------------

; Switch to M6520 when chip is available. 

; Standard SFR Symbols 
ACC     DATA    0E0H
B       DATA    0F0H
SP      DATA    81H
DPL     DATA    82H
DPH     DATA    83H
USER1   DATA    90H
DIR1    DATA    91H
FCTRL   DATA    0B2H
IPH     DATA    0B9H
IPL     DATA    0A9H
IRCON   DATA    0C0H
IEN0    DATA    0A8H
IEN1    DATA    0B8H

                NAME    ?C_STARTUP

?C_C51STARTUP   SEGMENT   CODE
?STACK          SEGMENT   IDATA

                RSEG    ?STACK
                DS      1

                EXTRN CODE (?C_START)
                PUBLIC  ?C_STARTUP
                PUBLIC  _?TRIM_TEST

                CSEG    AT      0
?C_STARTUP:     LJMP    STARTUP1
                RSEG    ?C_C51STARTUP
STARTUP1:
                CLR     IEN0^7          ; Disable interrupts
; To enable secure mode, remove the semicolon of the next line
;                ORL    FCTRL,#40H       ; set secure bit
                MOV     0E8h,#0FFh      ; Refresh nonmaskable watchdog.

; Set system interrupt priorities; more frequent are higher priority.
                MOV     IPH,#01DH       ; From code in options_gbl.h, main.c
                MOV     IPL,#00AH       ; From code in options_gbl.h
; Clear PLL_OK interrupt (bit3), and others
                MOV     IRCON,#0
; Enable PLL_OK interrupt
                MOV     DPTR,#2007H     ; Set EX_PLL
                MOV     A,#20H
                MOVX    @DPTR,A
; Enable interrupts
                MOV     IEN1,#08H       ; Enable INT4, the PLL_OK interrupt
                MOV     IEN0,#80H       ; Enable all interrupts

                ACALL   _?TRIM_TEST       ; Test 6521's trims

IF IDATALEN <> 0
                MOV     R0,#IDATALEN - 1
                CLR     A
IDATALOOP:      MOV     @R0,A
                DJNZ    R0,IDATALOOP
ENDIF

IF XDATALEN <> 0
                MOV     DPTR,#XDATASTART
                MOV     R7,#LOW (XDATALEN)
  IF (LOW (XDATALEN)) <> 0
                MOV     R6,#(HIGH (XDATALEN)) +1
  ELSE
                MOV     R6,#HIGH (XDATALEN)
  ENDIF
                CLR     A
XDATALOOP:      MOVX    @DPTR,A
                INC     DPTR
                DJNZ    R7,XDATALOOP
                DJNZ    R6,XDATALOOP
ENDIF

IF PPAGEENABLE <> 0
                MOV     PPAGE_SFR,#PPAGE
ENDIF

IF PDATALEN <> 0
                MOV     R0,#LOW (PDATASTART)
                MOV     R7,#LOW (PDATALEN)
                CLR     A
PDATALOOP:      MOVX    @R0,A
                INC     R0
                DJNZ    R7,PDATALOOP
ENDIF

IF IBPSTACK <> 0
EXTRN DATA (?C_IBP)
                MOV     ?C_IBP,#LOW IBPSTACKTOP
ENDIF

IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)
                MOV     ?C_XBP,#HIGH XBPSTACKTOP
                MOV     ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF

IF PBPSTACK <> 0
EXTRN DATA (?C_PBP)
                MOV     ?C_PBP,#LOW PBPSTACKTOP
ENDIF

                MOV     SP,#?STACK-1
                LJMP    ?C_START

; Read a trim whose index is in A. Return the trim in A.
                CSEG    AT 100H
FUSE_TABLE: 
                DB      0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff

; Trim test. Prefix "_?" tells Keil C it's reentrant.
_?TRIM_TEST:
                PUSH    IEN0
                PUSH    PSW             ; Save registers, so it's reentrant.
                MOV     PSW,00H         ; Select registers before saving them
                PUSH    DPL
                PUSH    DPH
                PUSH    ACC
                MOV     A,R7            ; Save R7 from the current register set.
                PUSH    ACC
                MOV     A,R6            ; Save R6 from the current register set.
                PUSH    ACC
                
                CLR     IEN0.7

; Wait for all fuses to be read once before checking fuses
; Complete fuse read takes 45 xtal clock cycles (1 fuse per xtal clock)
                MOV     R7,#21          ; Wait 21x4 = 48 cycles
loop_inner:     DJNZ    R7,loop_inner   ; 4 cycles (in brownout, 1 cycle/clk) 

                mov     DPH, #HIGH(FUSE_TABLE)

fuse_test_frst: ; check if values previously stored
                mov     DPL,#LOW(FUSE_TABLE)      
                clr     a
                movc    a,@a+dptr       ; read fuse table
                xrl     a,#55H
                jnz     fuse_save

                MOV     DPTR,#2003H     ; Check if in brownout mode
                MOVX    A,@DPTR
                JB      ACC.6,PASS      ; Mission mode, so don't check.                
fuse_test:
                mov     r7,#8           ; byte counter
fuse_test_lp1:
                mov     DPTR,#FUSE_TABLE    ; load pointer to fuse table
                mov     a,r7
                movc    a,@a+dptr       ; read fuse table
                mov     r6,a

                mov     a,r7 
            
                MOV     DPTR,#20FDH     ; TRIMSEL address
                MOVX    @DPTR,A         ; load reg to read trim
                MOV     DPL,#0FFH       ; TRIM value address

                MOVX    A,@DPTR         ; Get trim value

                cjne    a,06H,FAIL      ; test if flash read and trim ==
                djnz    r7,fuse_test_lp1
            
                JMP     PASS
fuse_save:
                MOV     DPTR,#2003H     ; Check if in brownout mode
                MOVX    A,@DPTR
                ; If brownout mode, don't save them and enter sleep.
                JNB     ACC.6,FAIL

            ;   mov     84H,#LOW(FUSE_TABLE)
                mov     r7,#8           ; byte counter
fuse_save_lp1:
                mov     a,r7 
            
                MOV     DPTR,#20FDH     ; TRIMSEL address
                MOVX    @DPTR,A         ; load reg to read trim
                MOV     DPL,#0FFH       ; TRIM value address

                MOVX    A,@DPTR         ; Get trim value
                mov     r6,a

                mov     a,r7 
                mov     dptr,#FUSE_TABLE
                add     a,DPL
                mov     DPL,a
                mov     a,r6

                orl     0B2H,#01H       ; set to flash write
                movx    @dptr,a         ; write fuse table byte
                djnz    r7,fuse_save_lp1

                mov     a,#55H          ; control byte to mark 

                mov     dptr,#FUSE_TABLE
                orl     0B2H,#01H       ; set to flash write
                movx    @dptr,a         ; write fuse table byte

                jmp     PASS

FAIL:
                MOV     DPTR,#20A9H     ; WAKE address
                MOV     A,#0C1H         ; SLEEP forces wake and fuse re-read
                MOVX    @DPTR,A

PASS:           CLR     A               ; Select 0
                MOV     DPTR,#20FDH     ; TRIMSEL address
                MOVX    @DPTR,A         ; clear trim select register.

                POP     ACC
                MOV     R6,A            ; Restore R7 in this register set
                POP     ACC
                MOV     R7,A            ; Restore R7 in this register set
                POP     ACC
                POP     DPH
                POP     DPL
                POP     PSW             ; Restore registers, so it's reentrant.
                POP     IEN0
                RET

                END

 

RTC例程

复位后,软件不应该马上调节时钟修正休眠模式下时差,而是首先计算需要消除的时间偏差,然会设置时钟进行补偿。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分