您的当前位置:首页正文

C8051F单片机程序丢失问题的原因分析

2021-11-13 来源:二三四教育网


C8051F单片机程序丢失问题的原因分析

1 C8051Fxxx单片机简单介绍和Flash结构

C8051Fxxx系列器件是Silicon Labs推出的一个高速单片机系列。这款单片机是完全集成的混合信号片上系统型MCU 芯片,具有高速、流水线结构的8051 兼容的CIP51内核;70%的指令的执行时间为1个或2个系统时钟周期;片上有丰富的片内外设,根据型号的不同,包括ADC、DAC、UART、捕捉/比较模块的可编程计数器/定时器阵列、SPI、SMBus等。

C8051Fxxx单片机有大容量的Flash存储器,用于程序代码和非易失性数据存储,可在系统编程。Flash的结构是以扇区为单位组织的(128 KB系列以1 024字节为1个扇区,64 KB系列以512字节为1个扇区)。非易失性Flash可以用来存储系统的参数,如软件版本、生产日期等。Flash可以使用编程器擦写,也可以在程序中使用MOVX指令来修改,从而使Flash 存储器具有在系统重新编程能力,允许现场更新8051 固件程序。Flash的写和擦除操作由硬件自动定时,以保证操作正确通过。C8051Fxxx的Flash保存下载的程序,在系统上电后,单片机从Flash读出代码数据到RAM,之后程序开始运行。

2 程序丢失问题的出现和原因

在一些实际应用中,系统重新上电后会出现程序不能正常运行的问题,常表现为“程序丢失”。通常是由于程序代码被损坏或被修改造成的。

造成程序丢失问题的原因很多,可以归结到一个基本原因,即对Flash的访问失败而造成Flash保存的代码出现错误。对于所有包含有Flash写/擦除子程序的系统,当CPU

工作在规定的VDD、温度、系统时钟频率范围之外时,对Flash进行写/擦除操作,都有可能出现Flash数据错误的现象。

2.1 Flash数据错误的硬件原因

C8051Fxxx单片机的Flash操作由硬件控制,所以硬件上的不稳定可能造成Flash操作错误。硬件原因主要是能影响CPU正常运行的因素,以及能影响Flash操作环境的因素。这些因素包括操作电压、温度以及外部干扰脉冲等,具体如下:

① 能影响CPU运行可靠性的参数有系统时钟源。如果系统时钟由外部晶振提供,外部的电磁干扰引起尖脉冲,并耦合到系统时钟上,则会导致不可预知的操作。

② 系统在单片机的工作电压没有稳定(VDD上升时间低于规定的1 ms)时就已经完成复位,由于系统复位时需要从Flash读出代码数据,Flash电压不稳定会出现不可预测的错误。

③ 在对Flash的操作过程中,如果温度、电压不稳定,也可能造成Flash数据错误。

2.2 Flash数据错误的软件原因

代码设计的缺陷是程序丢失的主要原因,因为单片机的Flash是由硬件来控制的,不能由软件来控制操作的细节,所以程序的不完善可能造成Flash的访问出错,从而使Flash数据出现错误。 这些操作包括: 在PSWE位(PSCTL.0)置1时CPU执行中断服务程序中的MOVX写操作,该中断服务程序要使用xdata 或pdata 的易失性存储区单元,这样可能导致向xdata 或pdata存储区写的数据写到Flash中了,从而出现问题。另外,如果

使用外部晶振作系统时钟,在时钟没有稳定时就对Flash进行写操作,也可能造成程序丢失。

3 程序丢失问题的解决方法

针对以上可能的原因,可以从软硬件两个方面来解决程序丢失问题。在硬件方面,主要是给系统提供稳定的工作环境,并避免外部干扰对CPU运行环境的影响;在软件方面,主要是规范对Flash的操作。

3.1 从硬件方面预防程序丢失

注意,以下的方法不是对所有的器件都适用,要根据具体的硬件情况选择相应的方法:

① 在RST引脚安装VDD监测电路,并将VDD监视设置为一个复位源(置RSTSRC.1为1)。这样如果系统电压不稳定,系统将自动复位,从而避免在电压不稳时访问Flash。

② 对外部晶振时钟2分频,更好的方法是使用内部振荡器,这样能提高系统时钟的抗干扰能力。

③ 如果使用外部晶振提供系统时钟,信号线应尽量靠近单片机的输入端,同时晶振外壳接地。

④ 对于使用外部晶振作时钟源的系统,应尽量增强晶振的驱动能力,这样也能在一定程度上预防程序丢失。

3.2 从软件方面预防程序丢失

程序丢失的主要原因是程序设计的缺陷,所以合理的程序代码设计能极大地预防该问题的出现。在代码中可以用多种方法来预防Flash数据丢失:

① 在PSWE=1下禁止中断,使得程序中的MOVX写指令是对Flash而不是对XRAM。

② 在PSWE=1下尽可能少地访问变量。在PSWE=0下执行地址译码操作,并用间接寻址方式执行MOVX写操作。例如,向Flash写多个字节,间接寻址和写PSWE过程如下:

unsigned char xdata * idata pwrite;//使用idata指针指向Flash

unsigned char *source;

unsigned char mydata;

for (addr = 0; addr <100; addr++) {

//PSWE =0时获取要写入的数据

mydata = *source++;

//PSWE =0时修改写入数据的目标地址

pwrite = (unsigned char xdata *) addr;

PSCTL = 0x01;//PSWE=1

//赋值方式写入数据,此时不执行目标地址的修改操作

*pwrite = mydata;

PSCTL = 0x00;//PSWE=0

}

以上代码中,当PSWE = 1时只执行写Flash操作(*pwrite = mydata);其他操作,如修改addr的值、获取源数据和目的地址,都是在PSWE = 0时执行的。

③ 将Flash写/擦除指针指向data或idata区。

④ 减少将PSWE置1的指令操作。理想的情况是只有两个操作将PSWE置1,即写1个Flash字节和擦除1个Flash字节。

⑤ 在Flash写/擦除函数中,使能VDD监视并设置复位源。使能和设置操作必须在实际的写操作发生之前,置PSWE=1之后完成。

⑥ 代码中所有的对RSTSRC的写操作均用直接赋值方式完成(如RSTSRC = 0x02),不能用读/写指令(如ORL或ANL)来完成。例如,代码“RSTSRC |= 0x02”是非法的。

⑦ 对于能用PORSF位来设置VDD为复位源的器件,保证在写RSTSRC时置PORSF=1,即先使能VDD为复位源,再使能其他复位源的操作,如时钟丢失监测(missing clock detector)、比较单元和软件复位。

4 一个实际应用方案

在有的应用场合,由于需要较快的执行速度,不能使用单片机的内部时钟作系统时钟源,所以使用外部晶振来提供时钟。在这种情况下,首先要在硬件上确保系统工作参数正常。

在软件上,由于最常见的Flash丢失原因是程序问题,所以可以在代码中用多种方法来预防Flash数据丢失。首先,在初始化单片机时,使能VDD检测,并设置VDD和时钟丢失为复位源。如果程序中有写/擦除Flash的代码,则在写/擦除操作前切换系统时钟,将系统时钟切到内部时钟或对外部时钟2分频;写/擦除操作完成之后,再恢复系统时钟,通过增加Flash修改操作时的时间开销来实现系统的稳定[2]。以下以C8051F126为例,给出了系统时钟切换的程序清单:

void SYSCLKAdjust(unsigned char select) {

EA_Save=EA;

SFRPAGE=0x0f;

switch(select) {

case 0x01:

OSCICN_Save = OSCICN;

CLKSEL_Save = CLKSEL;

OSCICN = 0xc3;//内部时钟,不分频

CLKSEL = 0x00;

break;

case 0x02:

OSCXCN_Save = OSCXCN;

OSCXCN |= 0x70;//外部时钟2分频

break;

default://选择内部时钟

OSCICN_Save = OSCICN;

CLKSEL_Save = CLKSEL;

OSCICN = 0xc3;

CLKSEL = 0x00;

break;

}

}

要恢复系统时钟到Flash操作前的状态,只需将CLKSEL_Save、OSCICN_Save、OSCXCN_Save重新写回到CLKSEL、OSCIN、OSCXCN。

C8051F126的系统时钟(SYSCLK)可以在内部时钟和外部时钟之间自由切换,切换时的操作要求如下:

① 在切换过程中,先设置所选时钟的属性,再用CLKSEL将其设置为SYSCLK。

② 在还原过程中,先用CLKSEL选择时钟源,再设置其属性。

③ 如果切换过程中关闭外部晶振,要再恢复外部时钟,启动后至少要等1 ms,再去读XTLVLD(OSCXCN.7)来判断晶振时钟是否稳定。否则,可能读到错误值。

④ 在外部时钟稳定运行后,再对其分频,不必插入等待周期。

⑤ 在切换过程中,可以保持外部时钟继续运行,这样在还原过程中就不必等待外部时钟稳定,从而节省时间开销,代价是系统功耗有所增加。

5 总结

程序丢失会带来各种不良的后果,最严重时致使程序无法正常运行,从而造成整个系统崩溃,给产品的应用带来麻烦。在系统的硬件设计和代码编写过程中,通过对以上问题

的注意,可以有效地防止程序丢失问题的出现。另外,由于系统时钟的切换只发生在Flash的写/擦除过程中,操作结束后又恢复成原来的设置,因而对系统运行速度的影响很小,从而保证了系统其他功能的实现。

FLASH Corruption

Problem

Areas of the FLASH code space on a device appear to be modified or corrupted inadvertently.

Solution

Any system that contains routines which write or erase FLASH memory involves some risk that the FLASH write/erase routines will execute if the CPU is operating outside its defined operating range of VDD, temperature, or system clock frequency. The goal is to minimize this risk by enabling FLASH writes and erases as little as possible (only one place in code can write to FLASH; only one place in code can erase FLASH) and by ensuring that the CPU is always operating in a defined mode. The most common causes of FLASH corruption are \"software\" based; that is, the CPU executes MOVX write operations while the PSWE bit is set to a '1'. This can happen if the CPU vectors to an interrupt service routine that performs an assignment to a variable located in xdata or pdata space. Some

devices, like the C8051F3xx families, include a FLASH Lock and Key sequence (FLKEY) to help minimize this risk.

Many things can be done in the code to prevent FLASH corruption, such as explicitly enabling the VDD monitor (where applicable) and disabling interrupts whenever PSWE = 1. Fortunately, there are some additional protection mechanisms that can make the system even more robust.

The most likely candidate for potential FLASH corruption is the CPU exiting reset prematurely (before VDD reaches Vrst) on initial power-on. This is usually caused by a system VDD rise time that is slower than the 1 ms specification in the datasheet (for 'F30x, 'F31x, and 'F33x family devices). One way to address this is to install an off-chip VDD brownout circuit on the /RST pin. Another way is to implement additional safeguards in code to ensure that the on-chip VDD monitor is always enabled whenever a write or erase to FLASH memory is attempted. Of course, it is also perfectly acceptable to implement both of these (hardware and software) schemes.

One other potential system parameter that can affect CPU code execution reliability is the system clock source. If the system clock is derived from an external crystal oscillator, then external EMI coupling can cause a runt pulse to be coupled into the system clock net which can lead to indeterminate operation. One way to lessen this risk is to enable the \"divide by 2\" option in the external crystal oscillator. Better ways are to use the internal oscillator or use an external CMOS can oscillator (one that is encased in a metallic shield to protect the sensitive crystal elements

from external coupling effects).

Another potential clock source related problem can occur on devices which are operating at system clock speeds of greater than 25 MHz. If a device is specified to operate at greater than 25 MHz, make certain that the Flash Read Timing bits (FLRT) located in the Flash Scale (FLSCL) register are set properly for the speed of the clock. If the CPU is operating at speeds above 25 MHz and the FLRT bits are not set properly, incorrect operation can occur because opcodes can be read incorrectly from the code memory.

These recommendations are summarized below:

Hardware Check List:

1. Use a good power supply decoupling strategy (both large and small ceramic capacitors) that comprehends ESD if ESD is a threat to your product (exposed connectors, etc. This includes any USB system with a connector.). Add Transient Voltage Suppression diodes on the power supply net if ESD is a threat.

2. Stress-test the system by cycling power frequently on the production units.

3. Stress-test the software by running it on a modified target board (all decoupling capacitors removed) and using a function generator to supply VDD (1 Hz triangle wave test and narrow (<1 us) deep (1.5 V below nominal VDD) pulse train test).

4. Make certain that in addition to the VDD monitor, the Missing Clock Detector is enabled as a reset source.

5. If using an external crystal, make sure the crystal traces are short and are protected by ground plane. Protect the external oscillator circuit from physical disturbances. Note that in addition to layout, crystals are also sensitive to temperature.

6. If the system is operating in an electrically noisy environment (high levels of EMI due to large switching currents or voltages, such as relays, motor control applications, or RF transmitters), use an external \"can\" oscillator if a precision time base is needed, or use the internal oscillator on the device. Do not use a crystal oscillator in these applications as electrical interference can cause the CPU to be exposed to \"runt\" pulses that violate the minimum system clock period high and low times.

7. Switch to the internal oscillator during Flash write or erase operations. The external oscillator can continue running, and the CPU can switch back to it when the Flash operation has completed.

8. If unable to switch to the internal oscillator, use XTAL/2. This will minimize the chance that a runt pulse will be presented to the CPU.

9. If unable to switch to the internal oscillator, poll for XTLVLD prior to the Flash operation to confirm that the oscillator is running and is stable.

10. If unable to switch to the internal oscillator, use a crystal drive strength that is one value higher than normal during the Flash operation, if possible.

11. If operating at system clock frequencies above 25 MHz, make certain that the Flash Read Timing bits in FLSCL are set appropriately for the operating frequency.

Simple Software Checklist:

12. Have exactly one routine which writes Flash memory and one routine that erases Flash memory. These should be the only two places in code where the PSWE bit is set to a '1'.

13. Disable interrupts when PSWE = 1 inside Flash write and erase routines.

14. Disable interrupts using \"EA = 0; EA = 0;\".

15. Minimize number of instructions between \"PSWE = 1\" and \"PSWE = 0\".

16. Perform any pointer address calculations or loop variable updates only while PSWE is '0'. Use a simple pointer dereference, for example \"*pwrite = the_data;\". Do not couple an address update with the dereference, such as \"*pwrite++ = the_data;\".

17. Explicitly locate Flash write pointers in 'data' or 'idata' segments, not 'pdata' or 'xdata'. Be cautious of using \"compact\" and \"large\" memory models as

these models will store automatic variables, such as pointers and loop counters, in 'pdata' and 'xdata' segments.

18. If writing a series of Flash bytes, bracket the pointer dereference with PSWE writes as follows:

unsigned char xdata * idata pwrite;

unsigned char *source;

unsigned char mydata;

for (addr = 0; addr < 100; addr++)

{

// perform any pointer math or complex

// dereferencing when PSWE = '0'

mydata = *source++;

// assign pointer when PSWE = '0'

pwrite = (unsigned char xdata *) addr;

// PSWE = 1

PSCTL = 0x01;

// initiate byte write using a simple

// dereference (no address increment or decrement)

*pwrite = mydata;

// PSWE = '0'

PSCTL = 0x00;

}

19. Find all instances in the code of writes to the Reset Sources register (RSTSRC), and confirm in each one that the VDD monitor is being explicitly enabled as a reset source. In particular, check any instances where code is trying to force a Software Reset, as many programmers will inadvertently disable the VDD monitor when forcing a Software Reset.

20. Also confim that all writes to RSTSRC use a direct assignment operator (=), and do not use a bit-wise operator such as \"|=\" or \"&=\".

21. Enable the VDD monitor and enable it as a reset source inside Startup.A51

(for Keil C51), or inside _sdcc_external_startup() (for SDCC). If using a different compiler, check your compiler documentation for modifying system start up code.

22. On devices which have a VDM0CN register, remove any delays between enabling the VDD monitor and enabling the VDD monitor as a reset source.

23. Enable the VDD monitor and enable it as a reset source inside your Flash write and erase routines, before the Flash write or erase operation happens.

24. For bootloading schemes, transmit the Flash lock and key sequence (0xa5, 0xf1 to be written to FLKEY) across the bootloading interface. Do not place the key sequence in code space if you do not have to.

25. For non bootloading schemes, derive the Flash lock and key sequence using an algorithm (such as XOR with 0x55), such that if program control enters the Flash write or erase routine by accident, an incorrect Flash key sequence will be delivered to the hardware, thus protecting the Flash memory.

26. For schemes in which Flash write/erase operations will not be needed until the next system reset, intentionally write an incorrect Flash Lock and Key sequence to FLKEY. This will cause the hardware to ignore any further write or erase attempts.

27. Perform address bounds checking inside the Flash write and erase routines. Generate a system reset if the target address is out of bounds (make

sure that you do not accidentally disable the VDD monitor as a reset source).

Advanced Software Checklist:

28. Using the linker (or compiler if it can do it), explicitly locate the Flash write and erase routines near the end of code space. This will help prevent them being accidentally executed due to a branch failure immediately above their entry point.

29. Place \"trap\" functions immediately before the Flash write and erase function entry points, such that if program control is \"falling through\" a previous routine, it will hit the trap instead of the Flash write/erase function. The trap routine should force a system reset.

因篇幅问题不能全部显示,请点此查看更多更全内容