此处的信息适用于:C51所有版本
症状
我添加了一个中断处理程序(ISR)到我的项目中,然而我却得到了如下的警告:
***WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?_WRITE_GMVLX1_REG?D_GMVLX1
CALLER1: ?PR?VSYNC_INTERRUPT?MAIN
CALLER2: ?C_C51STARTUP
***WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?_SPI_SEND_WORD?D_SPI
CALLER1: ?PR?VSYNC_INTERRUPT?MAIN
CALLER2: ?C_C51STARTUP
***WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?SPI_RECEIVE_WORD?D_SPI
CALLER1: ?PR?VSYNC_INTERRUPT?MAIN
CALLER2: ?C_C51STARTUP
上面这些都是什么?我该如何解决这个问题呢?
原因
Warning 15向我们表明了linker发现了一个函数,这个函数不仅在main code里被调用了,而且在ISR(或者被ISR调用的函数中)被调用了。或者是被同时被多个ISR同时调用了。
这样会产生一个问题,就是在此函数不是一个可重入函数,而当此函数已经在执行时它可能被另一个ISR所调用。这样就会导致结果是可变的而且很可能会导致一些参数的错误。
另一个问题就是本地变量和参数所使用的内存可能被其他函数的内存覆盖。如果函数是由中断所调用的,则此函数的内存就会被使用。这会引起其它函数的内存错误。
举例来说,对于你的第一个警告,WRITE_GMVLX1_REG是会被多个root所调用。其被定义在D_GMVLX1.C或者D_GMVLX1.A51中。他不仅会被ISR(或者被ISR调用的函数)而且也会被MAIN.C中的VSYNC_INTERRUPT函数所调用。
解决方法
有几种方法去解决这个问题
如果你100%确认这个函数的两个副本都不会同时执行(如果此函数是被main调用并且中断是未被使能的)并且此函数没有使用内存(只使用的寄存器),那么你就可以忽略此警告。
如果此函数使用了内存,你就要使用OVERLAY directive来将此函数从覆盖分析(overlay anaysis)中移除。举例如下:
OVERLAY (?PR?_WRITE_GMVLX1_REG?D_GMVLX1 ! *)
如上语句能阻止被此函数使用的内存遭到覆盖。如果这个函数调用了你程序中其他的在别处的函数,那么你可能需要将这些函数也排除在覆盖分析之外。
如果当此函数在执行时可以被调用,那么事情就会变得比较的复杂。你可能需要:
无论何时当从main中调用此函数时,需要关闭中断。你可能需要对被调用的函数使用#pragma disable。你也必须使用OVERLAY directive将此函数从overlay analysis中移除。为此函数创建两个副本。一个给main,一个给ISR。使此函数可重入。举例如下:void myfunc(void) reentrant {...
}
上面的定义会产生一个用来存储参数和本地变量的可重入的栈。如果使用了这种方法那么这个可重入的栈必须在STARTUP.A51中配置。这样会花费更多的RAM并且会减缓可冲入函数的执行。