上一节展示了如何使用“信号”属性用 C 语言编写一个 ISR,
以及这将如何导致部分执行上下文被自动保存(只有被 ISR 修改的处理器寄存器才会被保存)。
但是,执行上下文切换需要保存整个上下文。
应用程序代码可以在进入 ISR 时显式地保存所有处理器寄存器,
但这样做会导致一些处理器寄存器被保存两次——一次由编译器生成的代码保存,另一次由应用程序代码保存。这是
不希望出现的现象,可通过在“信号”属性之外使用 'naked' 属性来避免。
void SIG_OUTPUT_COMPARE1A( void ) __attribute__ ( ( signal, naked ) );
void SIG_OUTPUT_COMPARE1A( void )
{
/* ISR C code for RTOS tick. */
vPortYieldFromTick();
}
'naked' 属性可以防止编译器生成任何函数入口或出口代码。 现在,
编译代码会产生更简单的输出:
;void SIG_OUTPUT_COMPARE1A( void )
;{
; ---------------------------------------
; NO COMPILER GENERATED CODE HERE TO SAVE
; THE REGISTERS THAT GET ALTERED BY THE
; ISR.
; ---------------------------------------
; CODE GENERATED BY THE COMPILER FROM THE
; APPLICATION C CODE.
;vTaskIncrementTick();
CALL 0x0000029B ;Call subroutine
; ---------------------------------------
; NO COMPILER GENERATED CODE HERE TO RESTORE
; THE REGISTERS OR RETURN FROM THE ISR.
; ---------------------------------------
;}
当使用 'naked' 属性时,编译器不会产生任何函数入口或出口代码,
所以现在必须显式添加这个属性。 RTOS 宏 portSAVE_CONTEXT() 和 portRESTORE_CONTEXT()
分别用于保存和恢复整个执行上下文:
void SIG_OUTPUT_COMPARE1A( void ) __attribute__ ( ( signal, naked ) );
void SIG_OUTPUT_COMPARE1A( void )
{
/* Macro that explicitly saves the execution
context. */
portSAVE_CONTEXT();
/* ISR C code for RTOS tick. */
vPortYieldFromTick();
/* Macro that explicitly restores the
execution context. */
portRESTORE_CONTEXT();
/* The return from interrupt call must also
be explicitly added. */
asm volatile ( "reti" );
}
'naked' 属性可使应用程序代码完全控制保存 AVR 上下文的时间和方式。
如果应用程序代码在进入 ISR 时保存了整个上下文,
那么在执行上下文切换之前就不需要再次保存,因此没有处理器寄存器被保存两次。
下一节: RTOS 实现——FreeRTOS Tick 代码
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.
|