C2000 DSP中全局变量清零问题

一般情况下,未明确赋初值的全局变量会被自动清零,而且ANSI C中似乎也有这一规定,之前写程序都默认这是没有例外的规定了。然而,前段时间在调试28030程序的时候发现,未赋初值的全局变量并没有被清零,而是一个随机值,这说明在TI的DSP中,全局变量并不会自动清零。TI论坛中的这个讨论也证实了这一结论,由此可见,TI的编译器的确有些很特别的地方……下面来具体谈谈全局变量清零这个问题。

全局变量一般被称为.bss段,ARM编译器中也将其称为ZI-data段,即”Zero Initialize”之意。.bss段是不占用ROM空间的,程序运行起来后.bss段显然应该是在RAM中的,这就有一个问题,RAM中的.bss段是什么时候完成清零的呢?答案是在进入main()函数之前,由启动代码或库函数完成清零操作,如果使用了操作系统,则由Bootloader完成这一工作。

以ARM MDK附带的启动代码为例,在执行完使用汇编语言编写的启动代码后,程序并没有跳转到main()处,而是跳转到了__main()处执行。__main()函数是一个库函数,这个函数最重要的作用就是完成所谓的“段拷贝”工作,具体来说,就是完成了以下三个步骤:

  1. 将非零(只读和读写)运行区域从其载入地址复制到运行地址;
  2. 清零ZI-data区域(即.bss段);
  3. 跳转到__rt_entry,最终会跳转到main()处,用户程序开始执行。

由此可见,是否对全局变量进行清零完全是由启动代码和库函数决定的,而TI的编译器就没有链接完成这一工作所需的库函数,自然也就无法完成全局变量自动清零的工作了。解决这一问题的方法有两个:

  1. 在声明全局变量显式的赋初值0
  2. 程序中仿照__main()库函数的写法,自己写一个清零函数完成这一工作

值得注意的是,通过请教导师得知,这并不是TI编译器的设计缺陷,TI的编译器是专门这样设计的,这样设计的目的在于赋予程序员更大的灵活性。在某些情况下,是需要对全局变量进行选择性清零或其它操作的。

一个实际的例子是:假设使用了看门狗,在某些情况下系统看门狗复位了,对于某些控制系统而言,这时是要求系统在最短的时间内恢复之前的工作状态的。这种情况下,一般在程序开头加上一段检测代码,检测复位原因,如果是正常上电复位,则对全局变量进行清零操作;若判断出是看门狗复位,则自动执行之前的程序。系统软复位时并没有掉电,故RAM中的数据不会丢失。因为此时并没有对全局变量进行清零,之前的全局变量数据全部都在,此时就可以很快的恢复之前的工作状态,并且还可以使用一些全局变量辅助判断之前的错误复位的原因。

文章目录