Preguntas del examen para expertos integrados
Recomendación 1: OS_CPU.H
1. Defina tipos de datos que no estén relacionados con el compilador.
Simplemente escriba los tipos de datos correspondientes según diferentes compiladores. correspondiente al tipo de datos de ARM7 se escribe de la siguiente manera
typedef unsigned char BOOLEAN;/* variable booleana*/
typedef unsigned char INT8U /* variable entera de 8 bits sin signo*; /
typedef char INT8S con signo /* variable entera de 8 bits con signo*/
typedef unsigned short INT16U /* variable entera de 16 bits sin signo*/
<; p>typedef con signo corto INT16S; /* variable entera de 16 bits con signo*/typedef unsigned int INT32U; /* variable entera de 32 bits sin signo*/
typedef con signo int INT32S ; /* Variable entera de 32 bits con signo*/
typedef float FP32; /*Número de coma flotante de precisión simple (32 bits)*/
typedef double FP64; número de coma flotante (64 bits)*/
/*Seleccione INT32U de acuerdo con el ancho de la pila de ARM7 entre los tipos de datos definidos anteriormente*/
typedef INT32U OS_STK /* La pila es Ancho de 32 bits*/
La siguiente parte es el código escrito para ser compatible con los tipos de datos de versiones inferiores de UCOS, que no se considerarán en UCOS-II por el momento.
2 Código relacionado con el procesador
Primero defina el método de implementación de interrupción. Hay tres métodos de interrupción preestablecidos en ARM7, está configurado en el método 2
#define OS_CRITICAL_METHOD 2/. *Seleccione el método de activación o desactivación de interrupciones*/
El siguiente párrafo es una parte que aún no he entendido completamente. Solo sé que se configuran 12 funciones de interrupción de software cuando se llaman estas funciones.
Las cosas correspondientes al número de interrupción se ejecutarán antes.
Debería poder comprender completamente la implementación de las interrupciones de software después de verlo en detalle.
Este código se explicará en detalle en los siguientes archivos, por lo que no lo analizaré aquí por ahora.
p>Definición de pila El núcleo ARM7 admite dos métodos de crecimiento, pero el compilador del lenguaje ADS C solo admite el método de crecimiento de arriba hacia abajo. Por lo tanto:
#define OS_STK_GROWTH 1 /* La pila crece desde. de arriba a abajo, 0: el método de crecimiento de abajo hacia arriba*/
Las últimas líneas definen respectivamente el modo de usuario 01, el modo de sistema 1f y la instrucción de interrupción IRQ deshabilitada 80 tres. Un número inmediato, conveniente para llamar. .
También hay dos funciones predefinidas cuyas funciones se deben conocer más adelante, pero no se consideran por ahora. No son muy importantes.
Interrupción suave:
La interrupción no devuelve el formulario:
void _swi(swi_num) swi_name(argumentos);
Devuelve un resultado a R0
int _swi(swi_num) swi_name (argumentos);
Puede devolver hasta cuatro resultados R0-R3 a una estructura struct type{ int a,b,c,d}
type (tipo de retorno) _value_in_regs( Modificador que devuelve múltiples resultados) _swi(swi_num) swi_name(arguments);
He buscado muchos artículos en el blog sobre cómo implementar interrupciones suaves en ARM, pero no encontré nada que explique Es mejor verlo usted mismo.
El código trasplantado de ARM primero define un montón de números de interrupción suave, entre los cuales las subrutinas de servicio de interrupción de 0 y 1 están escritas en ensamblador.
p>Otros Todos están en la subrutina del servicio de interrupción SWI_Exception escrita en lenguaje C.
__swi(0x00) void OS_TASK_SW(void);
/* Función de cambio de tarea a nivel de tarea*/
__swi(0x01) void _OSStartHighRdy(void) ;
/* Ejecutar la tarea con la mayor prioridad*/
__swi(0x02) void OS_ENTER_CRITICAL(void);
/* Desactivar interrupciones*/
__swi(0x03) void OS_EXIT_CRITICAL(void);
/* Habilitar interrupciones*/
__swi(0x40) void *GetOSAddr(int Index);
/* Obtener la entrada de la función de servicio del sistema*/
__swi(0x41) void *GetUsrAddr(int Index);
/* Obtener la entrada de la función de servicio personalizada */ p>
__swi(0x42) void OSISRBegin(void);
/* Iniciar procesamiento de interrupción*/
__swi(0x43) int OSISRNeedSwap(void);
/* Determinar si es necesario cambiar la interrupción*/
__swi(0x80) void ChangeToSYSMode(void);
/* Cambiar la tarea al sistema mode*/
__swi(0x81) void ChangeToUSRMode(void);
/* Cambia la tarea al modo de usuario*/
__swi(0x82) void TaskIsARM (INT8U prio);
/* El código de la tarea es código ARM*/
__swi(0x83) void TaskIsTHUMB(INT8U prio);
/* El El código de tarea es THUMB */
Por ejemplo, cuando el programa se ejecuta y llama a la función OS_TASK_SW(void), se genera una interrupción de software y luego se ingresa la subrutina del servicio de interrupción.
¿Qué instrucciones se deben seguir? Bueno, simplemente siga el siguiente código. Este código sirve para conectar el controlador de excepciones de interrupción del software al kernel.
Se implementa en el código de inicio:
LDR PC, SWI_Addr
p>
SWI_Addr DCD SoftwareInterrupt
Entonces, cuando se genera una interrupción suave, la PC salta a SoftwareInterrupt y luego ingresa a la parte de procesamiento de interrupción de excepción de software
, y luego ejecute el siguiente código ensamblador SoftwareInterrupt
LDR SP, StackSvc
/*Reset the stack pointer*/
STMFD SP!, {R0-R3 , R12, LR}
/*Guardar R0, R1, R2, R3, R12, LR (R14), preste atención a por qué solo se guardan estos pocos
registros, porque R4-R11 almacena variables locales y el compilador las protege automáticamente*/
MOV R1, SP /* R1 apunta a la ubicación de almacenamiento de parámetros*/
MRS R3, SPSR /
*Guardar el registro de estado del modo de gestión*/
TST R3, #T_bit /* Si estaba en estado Thumb antes de la interrupción*/
LDRNEH R0, [LR,#-2 ] /* Si es así, obtenga el número SWI del estado del pulgar*/
BICNE R0, R0, #0xff00 /*El número de función SWI del comando THUMB es de 8 dígitos*/
LDREQ R0, [LR,#- 4] /* Si es cero, la instrucción ARM obtiene el número SWI*/
BICEQ R0, R0, #0xFF000000
/*En la instrucción ARM configurado, el número de función SWI es de 24 bits, por lo que el valor alto es 8 bits claro r0=número SWI*/
CMP R0, #1 /*
LDRLO PC, =OSIntCtxSw /* Dudoso */
/* El número de función es 0 para OSIntCtxSw para ejecutar la función de cambio de tarea de interrupción */
LDREQ PC, =__OSStartHighRdy/*SWI es 1 y el primero cambio de tarea*/
BL SWI_Exception /* De lo contrario, ingrese la función de interrupción escrita en c*/
LDMFD SP!, {R0-R3, R12, PC}/*R0-R3, R12, LR pop */
StackSvc p>
DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)
¿Cómo ingresar a la subrutina del servicio de interrupción SWI_Exception escrita en C? A través de la siguiente declaración
IMPORTAR SWI_Exception; controlador de excepción de interrupción suave
significa conectar la función en el programa c en este código ensamblador, la misma razón
EXPORTAR __OSStartHighRdy
EXPORTAR OSIntCtxSw; Entrada cuando sale la interrupción
Ver IRQ_Handler en startup.s
EXPORTAR SoftwareInterrupt Declaración sobre la entrada de interrupción suave El código ensamblador está enlazado a el exterior,
Por lo tanto, el nombre de la función se puede llamar directamente desde el exterior
Continúe mirando otras partes del código OS_CPU_A.S, que son dos procesamiento de interrupciones de excepción de software Los códigos Las funciones OSIntCtxSw y OSStarHighRdyOSIntCtxSw se llaman cuando la subrutina del servicio de interrupción pone una tarea de mayor prioridad en el estado listo y necesita cambiar a la tarea después de que regresa la interrupción. Esto se debe a que el valor del registro de CPU de la tarea conmutada ha cambiado después. responder a la interrupción se almacena en la pila, por lo que no es necesario guardarlo repetidamente y simplemente cambiar de tarea directamente para el proceso específico, consulte el código OSIntCtxSw
; entorno de tareas cuando responde a la interrupción de excepción del software, ingresa al modo de sistema. En el código anterior, podemos ver que la estructura de la pila guardada al ingresar al modo de sistema es: R0, R1, R2, R3, R12, LR de arriba a abajo. abajo, mientras que la estructura de pila de la tarea en modo de usuario debe ser: OsEnterSum, CPSR, RO-12, LR, PC, por lo que la estructura de pila de la tarea original debe guardarse antes de cambiar las tareas de interrupción del software.
LDR R2, [SP, #20] ;Obtener PC
LDR R12, [SP, #16] ;Obtener R12
MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode)
MOV R1, LR
STMFD SP!, {R1-R2} ;Guardar LR, PC
STMFD SP! , {R4-R12} ;Guardar R4-R12 MSR CPSR_c, R0
LDMFD SP!, {R4-R7} ;Obtener R0-R3
AGREGAR SP, SP, #8 ;Pop R12, PC
MSR CPSR_c, #(NoInt | SYS32Mode)
STMFD SP!, {R4-R7} ;Guardar R0-R3
LDR R1, =OsEnterSum; Obtener OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3}; Guardar CPSR, OsEnterSum; TCB actual de la tarea
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1] BL OSTaskSwHook función de gancho de llamada
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1] BL OSTaskSwHook p >
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR
R6, [R4]
OSIntCtxSw_1
;Obtener nuevo puntero de pila de tareas
LDR R4, [R6]
AGREGAR SP, R4 , #68 ;17 registro CPSR, OsEnterSum, R0-R12, LR, SP
LDR LR, [SP, #-8]
MSR CPSR_c, #(NoInt | SVC32Mode) ;Entrar en modo de gestión
MOV SP, R4 ;Establecer puntero de pila LDMFD SP!, {R4, R5} ;CPSR,OsEnterSum
;Restaurar OsEnterSum de nueva tarea
LDR R3, =OsEnterSum
STR R4, [R3]
MSR SPSR_cxsf, R5;Restaurar CPSR
LDMFD SP!, {R0-R12, LR, PC }^ ;Ejecutar nueva tarea
__OSStartHighRdy
MSR CPSR_c, #(NoInt | SYS32Mode) ;Ajustar al modo de administración
;Dígale a uC/OS -II ya se está ejecutando
LDR R4, =OSRunning
MOV R5, #1
STRB R5, [R4] Marcar el indicador de ejecución multitarea; como verdadero BL OSTaskSwHook; llame a la función de enlace para ejecutar la función definida por el usuario LDR R6, =OSTCBHighRdy almacena la dirección del bloque de control de la tarea lista de mayor prioridad
LDR R6, [R6]
B OSIntCtxSw_1; Vaya al código de la parte de salto de tarea del bloque de función de retorno de interrupción escrito anteriormente, porque ambas funciones usarán esta parte del código y el control de tarea de la tarea lista de alta prioridad antes de ingresar a esta. código La dirección rápida se almacena en R6.
AREA SWIStacks, DATA, NOINIT,ALIGN=2
SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ;Código del espacio de pila del modo de gestión OSIntCtxSw_1: OSIntCtxSw_1
;Obtener nuevo puntero de pila de tareas
LDR R4, [R6] ;El puntero de pila del bloque de control de tareas se colocó en R6 y ahora se coloca en R4
ADD SP, R4, #68;17 registros CPSR, OsEnterSum, R0- R12, LR,SP
LDR LR, [SP, #-8]
MSR CPSR_c, #(NoInt | SVC32Mode) ;Ingrese al modo de administración
MOV SP, R4;Establece el puntero de pila, R4 almacena el puntero de pila no modificado LDMFD SP!, {R4, R5};CPSR,OsEnterSum
;Restaura el OsEnterSum de la nueva tarea
LDR R3 , =OsEnterSum
STR R4, [R3]
MSR SPSR_cxsf, R5 ;Restaurar CPSR
LDMFD SP!, {R0-R12, LR, PC} ^; Ejecute una nueva tarea, restaure la escena y regrese del procesamiento de excepciones; la lista de registros de la instrucción de retorno de interrupción debe incluir el símbolo ^ después de la PC, lo que indica que se trata de una forma especial de instrucción. Esta instrucción carga la PC desde la memoria y restaura el CPSR. El puntero de pila SP utilizado aquí es un registro que pertenece al modo de excepción, y cada modo de excepción tiene su propio puntero de pila.
SoftwareInterrupt
LDR SP, StackSvc; Restablecer puntero de pila
STMFD SP!, {R0-R3, R12, LR}; Guardar registro
MOV R1, SP ; R1 apunta a la ubicación de almacenamiento de parámetros MRS R3, SPSR
TST R3, #T_bit; Si estaba en estado Thumb antes de la interrupción
LDRNEH R0, [LR,#-2] ; Sí: Obtener el número SWI del estado del pulgar
BICNE R0, R0, #0xff00
LDREQ R0, [LR,#-4] No: Obtener el número SWI del estado del brazo
BICEQ R0, R0, #0xFF000000
; r0 = número SWI, R1 apunta a la ubicación de almacenamiento de parámetros
CMP R0, #1
LDRLO PC, =OSIntCtxSw
LDREQ PC, =__OSStartHighRdy; SWI 0x01 es la primera tarea que cambia BL SWI_Exception
LDMFD SP!, {R0-R3, R12, PC}^ p>
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)OSIntCtxSw
;El siguiente es el entorno de tareas para guardar
LDR R2, [SP, #20] ;Obtener PC (LR)
p>LDR R12, [SP, #16] ;Obtener R12
MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode)
MOV R1, LR p>
STMFD SP!, {R1-R2} ;Guardar LR,PC
STMFD SP!, {R4-R12} ;Guardar R4-R12 MSR CPSR_c , R0
LDMFD SP!, {R4-R7} ;Obtener R0-R3
AGREGAR SP, SP, #8 ;Pop R12,PC
MSR CPSR_c, #(NoInt | SYS32Mode)
<p> STMFD SP!, {R4-R7} ;Guardar R0-R3
LDR R1, =OsEnterSum ;Obtener OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3}; Guardar CPSR, OsEnterSum; Guarda el puntero de la pila de tareas actual en el TCB
LDR R1, =OSTCBCur
LDR R1, [ R1 ]
STR SP, [R1] BL OSTaskSwHook ;Función de gancho de llamada
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4] ; Pasar la tarea lista de mayor prioridad de OSPrioHighRdy a OSPrioCur
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4] ; Pasa el puntero del bloque de control de tareas de mayor prioridad al puntero del bloque de control de tareas actual
En cuanto a las interrupciones y los tiempos de reloj, UCOS-II es el ensamblaje y c de la rutina de servicio de interrupción universal ARM7. La interfaz de la función es la siguiente: las directivas MACRO y MEND se utilizan para la definición de macro, MACRO identifica el comienzo de la definición de macro y MEND identifica el final de la definición de macro.
Después de la definición, puede llamar a este código varias veces en el programa mediante instrucciones macro MACRO
$IRQ_Label HANDLER $IRQ_Exception_ EXPORT $IRQ_Label; Etiqueta de salida
IMPORT $IRQ_Exception_ Etiqueta de referencia externa $; IRQ_Label
SUB LR, LR, #4; Calcular dirección de devolución
STMFD SP!, {R0-R3, R12, LR}; MRS R3, SPSR; Guardar estado
STMFD SP, {R3, SP, LR}^ Guardar R3, SP, LR del estado del usuario, tenga en cuenta que no se puede volver a escribir
; Si se vuelve a escribir el SP del usuario, el SP debe ajustarse más tarde
LDR R2, =OSIntNesting++
LDRB R1, [R2]
AGREGAR R1, R1, #1
STRB R1, [R2] SUB SP, SP, #4*3
MSR CPSR_c, #(NoInt | SYS32Mode) ; mode
p>CMP R1, #1
LDREQ SP, =StackUsr
BL $IRQ_Exception_ ; Llame al controlador de interrupciones del lenguaje c MSR CPSR_c, #(NoInt SYS32Mode); cambia al modo del sistema
LDR R2, =OsEnterSum; OsEnterSum, para que la interrupción se desactive cuando OSIntExit sale
MOV R1, #1
STR R1, [R2] BL OSIntExit LDR R2, =OsEnterSum Debido a que la rutina del servicio de interrupción necesita salir, OsEnterSum=0
MOV R1, #0
STR R1, [R2] MSR CPSR_c, #(NoInt | IRQ32Mode); volver al modo irq
LDMFD SP, {R3, SP, LR}^; Restaurar el estado del usuario R3, SP, LR, tenga en cuenta no hacerlo; escribir de nuevo
Si lo que se escribe de nuevo es el SP del usuario, entonces el SP debe ajustarse más adelante
>
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1 AGREGAR SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; No realizar cambio de tareas
LDR PC, =OSIntCtxSw; Realizar cambio de tareas
MEND 2: Los archivos OS_CPU_C.C requieren que el usuario escriba 10 funciones C simples, pero solo 1 A. La función es necesaria y el resto de las funciones deben declararse, pero no necesariamente contienen ningún código. Después de una mirada aproximada, parece que se usa para depurar. Lo único que debe escribirse es OSTaskStkInit (). La función de la función OSTaskStkInit () es inicializar la estructura de pila de la tarea. La estructura de pila de la tarea está estrechamente relacionada con la arquitectura de la CPU y el compilador. Desde la estructura ARM, se puede escribir la siguiente estructura de pila: contador de programa PC, vinculador de programa LR, R12-R1, R0 se usa para pasar el primer parámetro pdata, CPSR/SPSR, contador de interrupciones fuera (usado para contar el número de interrupciones off , realizando así el anidamiento de interrupciones), el puntero de dirección devuelto apunta a los últimos datos almacenados, no a una dirección vacía. Excepción de interrupción de software Programa de servicio SWI Parte del lenguaje C void SWI_Exception (int SWI_Num, int *Regs): el parámetro SWI_Num corresponde al número de función definido en el archivo anterior, de las cuales las funciones 0 y 1 se definen en el archivo posterior, solo otras Aquí se definen 10 funciones. 2 y 3 corresponden respectivamente a la interrupción de apagado y la interrupción de encendido: MRS R0, SPSR // Cuando el software interrumpe, el registro de guardado del estado del programa SPSR se opera directamente, que es la operación del CPSR
ORR R0, R0, #NoInt //En lenguaje ensamblador, use ORR para establecer la posición correspondiente del registro y use BIC para borrarlo.
MSR SPSR_c, R0 //SPSR_c representa el 8- código de bits que solo cambia la sección de control de SPSR, y los otros tres Los bits de bandera en los segmentos _f, _s y _x están en el segmento _f, y los otros bits son bits reservados para habilitar interrupciones: MRS R0, SPSR //En habilitación interrupciones, es básicamente lo mismo que el anterior, excepto que ORR se cambia a BIC clear
BIC R0, R0, #NoInt
MSR SPSR_c, R Debido a la necesidad de implementar interrupciones Al anidar, las interrupciones solo se pueden habilitar cuando el contador que deshabilita las interrupciones disminuye a 0, y cada vez que se deshabilita la interrupción, este contador debe incrementarse en 1. Además, utilice la instrucción _asm al insertar lenguaje ensamblador.
80, 81, 82 y 83 corresponden respectivamente al modo del sistema, modo de usuario, conjunto de instrucciones ARM y conjunto de instrucciones THUMB: MRS R0, SPSR
BIC R0, R0, #0x1f //Primero. cambiar el modo de control Borrar los 5 bits inferiores
ORR R0, R0, #SYS32Mode //Establecer en 1F en modo sistema
MSR SPSR_c, R0 Modo de usuario: MRS R0, SPSR
BIC R0, R0, #0x1f
ORR R0, R0, #USR32Mode //Establecer en modo de usuario 10
MSR SPSR_c, conjunto de instrucciones R0 ARM y THUMB conjunto de instrucciones El código es el siguiente: ptcb = OSTCBPrioTbl[Regs[0]];
if (ptcb != NULL)
{
ptcb -> OSTCBStkPtr[1] & = ~(1 << 5);
} ptcb = OSTCBPrioTbl[Regs[0]];
if (ptcb != NULL)
{
ptcb -> OSTCBStkPtr[1] |= (1 << 5);
} Vi esto ayer y me di cuenta de que el lugar donde puedo' No se deje engañar por el concepto de bloque de control de tareas OS_TCB en UCOS, por lo que la tarea de hoy es echar un vistazo a esta parte. . . Probablemente recordé lo que hice anoche y comencemos el trabajo de hoy.
Paso a paso, aprende todo lo que no sabes y aprende todo lo que no sabes. . . No hay problema siempre y cuando trabajes duro. . . . . . __OSStartHighRdy
MSR CPSR_c, #(NoInt | SYS32Mode) ;MSR: en ARM, solo MSR puede configurar directamente el registro de estado CPSR o SPSR, que puede ser un número inmediato o un registro de origen, lo que significa que las interrupciones son. deshabilitado y SYS32Mode es el modo del sistema
;Dígale a uC/OS-II que ya se está ejecutando
LDR R4, =OSRunning ;OSRunning es una señal de que se está ejecutando multitarea, = OSRunning carga la dirección de OSRunning en R4. Lo que se almacena en R4 es una dirección. . .
MOV R5, #1
STRB R5, [R4] ; Almacene R5 en la variable OSRunning en la dirección almacenada en R4, es decir, configure OSRunning en 1 BL OSTaskSwHook; La función de enlace, OSTaskSwHook, se utiliza para la expansión y ejecuta funciones definidas por el usuario al cambiar de tarea. LDR R6, =OSTCBHighRdy; OSTCBHighRdy apunta al puntero al bloque de control TCB de la tarea de mayor prioridad. ! ! Coloque la dirección del puntero en R6.
LDR R6, [R6] ; Lee los datos en la dirección R6, es decir, la dirección de OSTCBHighRdy y colócalos en R6
B OSIntCtxSw_1 Salta a OSIntCtxSw_1 AREA SWIStacks, DATA, NOINIT ,ALIGN=2
SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ;El espacio de pila del modo de administración continúa con el código OSIntCtxSw que no leí ayer
;El siguiente es el entorno de tareas guardadas
LDR R2, [SP, #20] ;Obtener PC y ponerlo en R2
LDR R12, [SP, #16] ;Obtener R12, //¿Qué almacena R12?
MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode) ;Entra en modo sistema y desactiva las interrupciones
MOV R1, LR ;R1 pone el valor de LR
STMFD SP!, {R1-R2} ;Guardar LR, PC, almacenar R1, R2 en SP
STMFD SP!, {R4-R12} ;Guardar R4-R12, almacenar R4-12 SP MSR CPSR_c, R0 ;Volver al modo anterior
LDMFD SP!, {R4-R7} ;Obtener R0-R3
ADD SP, SP, #8 ;Abre la pila R12, PC
MSR CPSR_c, #(NoInt | SYS32Mode)
STMFD SP!, {R4-R7} ;Guardar R0-R3
LDR R1, =OsEnterSum ; Obtener OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3}; Guardar CPSR, OsEnterSum Guarda el puntero de la pila de tareas actual en el TCB actual; tarea
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1] BL OSTaskSwHook Llamar a la función de enlace
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4]
OSIntCtxSw_1
;Obtener el nuevo puntero de pila de tareas
LDR R4, [ R6 ] ;Asigne el puntero OSTCBHighRdy que apunta al bloque de control TCB de la tarea de mayor prioridad a R4
AGREGAR SP, R4, #68 ;17 registro: CPSR, OsEnterSum, R0-R12, LR, SP
LDR LR, [SP, #-8] ;Eliminar LR y ponerlo en LR
MSR CPSR_c, #(NoInt | SVC32Mode) ;Ingresar al modo de administración y mantener las interrupciones deshabilitadas p>
MOV SP, R4 ;Establezca el puntero de pila LDMFD SP!, {R4, R5} ;CPSR,OsEnterSum. Los datos LDMFD se sacan de la pila y se colocan en R4, R5
;Restaura el OsEnterSum de la nueva tarea
LDR R3, =OsEnterSum;La dirección de OsEnterSum se almacena en R3
STR R4, [R3] ;Asignar el valor de R4 a OsEnterSum
MSR SPSR_cxsf, R5 ;Restaurar CPSR; modificar SPSR en modo de gestión
LDMFD SP !, {R0-R12 , LR, PC }^ ;Ejecute nuevas tareas, restaure la escena y regrese del manejo de excepciones