Este artículo hace referencia a [Wildfire EmbedFire] "Implementación de kernel de subprocesos RT y desarrollo de aplicaciones: basado en STM32", que solo se usa como una nota de estudio personal. Para obtener contenido y pasos más detallados, consulte el texto original (puede descargarlo del Centro de descarga de datos de Wildfire)
Directorio de artículos
Cuando obtiene un proyecto RT-Thread trasplantado, va a la función principal, solo puede ver el código para crear hilos e iniciar hilos, inicialización de hardware, inicialización del sistema e iniciar el programador en la función principal. Eso es porque RT-Thread extiende la función principal y hace todo el trabajo antes de la función principal.
--original
Función de reinicio Reset_Handler
Después de encender el sistema, la primera función es la función de reinicio en el archivo de inicio. Este archivo de inicio está escrito en lenguaje ensamblador. La función de reinicio llamará a la función de biblioteca C. __main
El trabajo principal de esta función es inicializar el montón del sistema. y apilar, y finalmente llamar a la main()
función para entrar.El mundo del lenguaje C.
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
$Sub$$función principal
El texto original decía que después de la ejecución de un solo paso
__main
, saltaría acomponent.c
la$Sub$$main()
función, pero__main
después de un solo paso, fui directamente a lamain()
función (esto puede deberse a que mi operación no está en su lugar).
En el compilador de Keil, existe un par de símbolos, y pueden extender una función, como el uso $Sub$$
puede ejecutarse antes de la ejecución , y luego llamarse para cambiar a la función.$Super$$
$Sub$$main()
main()
$Sub$$main()
$Super$$main()
main()
Estas son component.c
algunas de las funciones en (para el compilador Keil)
extern int $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
/* the system main thread */
void main_thread_entry(void *parameter)
{
extern int main(void);
extern int $Super$$main(void);
#ifdef RT_USING_COMPONENTS_INIT
/* RT-Thread components initialization */
rt_components_init();
#endif
/* invoke system main function */
$Super$$main(); /* for ARMCC. */
}
función rtthread_startup()
$Sub$$main()
Solo hay una función en la función del paso anterior rtthread_startup()
, y toda la inicialización de RT-Thread se implementa en esta función.
Entre ellos, rt_hw_board_init()
esta función se ha tocado muchas veces y se define board.c
para inicializar el firmware subyacente.
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* board level initialization
* NOTE: please initialize heap inside board initialization.
*/
rt_hw_board_init();
/* show RT-Thread version */
rt_show_version();
/* timer system initialization */
rt_system_timer_init();
/* scheduler system initialization */
rt_system_scheduler_init();
/* create init_thread */
rt_application_init();
/* timer thread initialization */
rt_system_timer_thread_init();
/* idle thread initialization */
rt_thread_idle_init();
/* start scheduler */
rt_system_scheduler_start();
/* never reach here */
return 0;
}
función rt_application_init()
rt_application_init()
Se crea un subproceso en la función, que es un subproceso inicial. Cuando todos los subprocesos de la aplicación se crean correctamente, el subproceso inicial se cierra solo. La última línea de la función llama a la rt_thread_startup()
función. Aunque sabemos que la función de esta función es iniciar el subproceso, el subproceso no se inicia en este momento, porque la rtthread_startup()
última línea de la función de nivel superior (ver arriba) rt_system_scheduler_start()
no se ha iniciado. aún no se ha ejecutado y el subproceso del sistema aún no ha comenzado a programarse.
void rt_application_init(void)
{
rt_thread_t tid;
#ifdef RT_USING_HEAP
tid = rt_thread_create("main", main_thread_entry, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(tid != RT_NULL);
#else
rt_err_t result;
tid = &main_thread;
result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(result == RT_EOK);
/* if not define RT_USING_HEAP, using to eliminate the warning */
(void)result;
#endif
rt_thread_startup(tid);
}
función main_thread_entry()
La siguiente es la función de entrada del subproceso inicial, la función principal es inicializar el componente y finalmente $Super$main()
volver a llamar a main()
la función.
#ifndef RT_USING_HEAP
/* if there is not enable heap, we should use static thread and stack. */
ALIGN(8)
static rt_uint8_t main_stack[RT_MAIN_THREAD_STACK_SIZE];
struct rt_thread main_thread;
#endif
/* the system main thread */
void main_thread_entry(void *parameter)
{
extern int main(void);
extern int $Super$$main(void);
#ifdef RT_USING_COMPONENTS_INIT
/* RT-Thread components initialization */
rt_components_init();
#endif
/* invoke system main function */
#if defined(__CC_ARM) || defined(__CLANG_ARM)
$Super$$main(); /* for ARMCC. */
#elif defined(__ICCARM__) || defined(__GNUC__)
main();
#endif
}
función principal
main()
La función se llama a través del subproceso inicial. Como se mencionó anteriormente, el subproceso inicial debe cerrarse solo más tarde, lo que significa que main()
después de que se ejecuta la función, todo el sistema es main()
irrelevante. Esto es muy diferente del sistema bare metal. main()
Hay una función en el sistema bare metal, por lo que la función no deja de ejecutarse while(1)
después de encender el microcontrolador , mientras que RT-Thread (y algunos otros RTOS) no contienen un bucle infinito . , en cambio, es la creación e inicialización de un montón de subprocesos.main()
main()
En este punto, básicamente se ha presentado todo el proceso de inicio de RT-Thread. main()
No se discutirá aquí cómo funciona el sistema una vez que se completa la operación.