首先这是 startup.s 下的文件。
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000080
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000200
USR_Stack_Size EQU 0x00000500
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
运行时Stack_Top =IRQ stack top =0x40002178;
Supervisor Mode stack top = 0x40001f78;
user mode stack top = 0x40001ef8;
串口中断程序如下
void UART0_Exception(void)
{
uint8 IIR, temp;
OS_ENTER_CRITICAL();
while(((IIR = U0IIR) & 0x01) == 0)
{ /* 有中断未处理完 */
switch (IIR & 0x0e)
{
case 0x02: /* THRE中断 */
//for (i = 0; i < UART0_FIFO_LENGTH; i++) /* 向发送FIFO填充数据 */
// {
if (QueueRead(&temp, UART0SendBuf) == QUEUE_OK)
{
U0THR = temp;
}
else
{
U0IER = U0IER & (~0x02); /* 队列空,则禁止发送中断 */
}
// }
break;
case 0x04: /* 接收数据可用 */
case 0x0c: /* 字符超时指示 */
do /* 读取FIFO全部数据 */
{
QueueWrite((void *)UART0_ReceiveBuf,U0RBR);
}while((U0LSR & 0x00000001) != 0);
OSSemPost(Uart0Sem);
break;
case 0x06:
temp = U0LSR;
break;
default :
break;
}
}
VICVectAddr = 0; // 通知中断控制器中断结束
OS_EXIT_CRITICAL();
}
在进入串口中断时SP = 0x400021e8;mode为 system;
子函数
uint8 QueueRead(QUEUE_DATA_TYPE *Ret, void *Buf)
{
uint8 err;
DataQueue *Queue;
err = NOT_OK;
if (Buf != NULL) /* 队列是否有效 */
{ /* 有效 */
Queue = (DataQueue *)Buf;
OS_ENTER_CRITICAL();
if (Queue->NData > 0) /* 队列是否为空 */
{ /* 不空 */
*Ret = Queue->Out[0]; /* 数据出队 */
Queue->Out++; /* 调整出队指针 */
if (Queue->Out >= Queue->End)
{
Queue->Out = Queue->Buf;
}
Queue->NData--; /* 数据减少 */
err = QUEUE_OK;
}
else
{ /* 空 */
err = QUEUE_EMPTY;
if (Queue->ReadEmpty != NULL) /* 调用用户处理函数 */
{
err = Queue->ReadEmpty(Ret, Queue);
}
}
OS_EXIT_CRITICAL();
}
return err;
}
在进入上面函数的OS_ENTER_CRITICAL();时
首先经过软中断
;软件中断
SoftwareInterrupt
LDR SP, StackSvc ; 重新设置堆栈指针
STMFD SP!, {R0-R3, R12, LR}
MOV R1, SP ; R1指向参数存储位置
stackSvc = 0x400021f4;
而中断堆栈也是0x400021e8;这两个堆栈在运行过程中重叠。