RT-Thread(一)-快速上手
新换的工作目前的工程跑在RT-Thread上,虽然听说过这个操作系统,但是没有在这个操作系统上做过开发,所以打算尽快熟悉起来。
目前手头没有开发版,所以先试用模拟器熟悉下:Keil模拟器STM32F103 (rt-thread.org)。
按照文档二话不说先把例程跑起来:

1.$Super$$和$Sub$$
在keil 的ARM Development Tools中找到对应的介绍:

告诉了我们这个用法:
1.$Super$$foo:标识原始函数foo,使用它直接调用原始函数foo。
2.$Sub$$foo:标识调用的新函数,也就是对原始函数foo的扩展函数。

根据上边的介绍我们对例程中的led函数进行下扩展实验:

有了以上的实验,对这个$Super$$和$Sub$$的使用有了初步的了解,下面再进行系统启动代码的分析。
2.系统启动代码
2.1startup_stm32f103xe.s
;******************** (C) COPYRIGHT 2017 STMicroelectronics ******************** ;* File Name : startup_stm32f103xe.s ;* Author : MCD Application Team ;* Version : V4.2.0 ;* Date : 31-March-2017 ;* Description : STM32F103xE Devices vector table for MDK-ARM toolchain. ;* This module performs: ;* - Set the initial SP ;* - Set the initial PC == Reset_Handler ;* - Set the vector table entries with the exceptions ISR address ;* - Configure the clock system ;* - Branches to __main in the C library (which eventually ;* calls main()). ;* After Reset the Cortex-M3 processor is in Thread mode, ;* priority is Privileged, and the Stack is set to Main. ;******************************************************************************** ;* ;* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2> ;* ;* Redistribution and use in source and binary forms, with or without modification, ;* are permitted provided that the following conditions are met: ;* 1. Redistributions of source code must retain the above copyright notice, ;* this list of conditions and the following disclaimer. ;* 2. Redistributions in binary form must reproduce the above copyright notice, ;* this list of conditions and the following disclaimer in the documentation ;* and/or other materials provided with the distribution. ;* 3. Neither the name of STMicroelectronics nor the names of its contributors ;* may be used to endorse or promote products derived from this software ;* without specific prior written permission. ;* ;* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ;* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ;* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ;* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE ;* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ;* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ;* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ;* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ;* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; ;******************************************************************************* ; Amount of memory (in bytes) allocated for Stack ; Tailor this value to your application needs ; <h> Stack Configuration ; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp ; <h> Heap Configuration ; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Heap_Size EQU 0x00000200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit PRESERVE8 THUMB ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler ; External Interrupts DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; Tamper DCD RTC_IRQHandler ; RTC DCD FLASH_IRQHandler ; Flash DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line 0 DCD EXTI1_IRQHandler ; EXTI Line 1 DCD EXTI2_IRQHandler ; EXTI Line 2 DCD EXTI3_IRQHandler ; EXTI Line 3 DCD EXTI4_IRQHandler ; EXTI Line 4 DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1 DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 DCD ADC1_2_IRQHandler ; ADC1 & ADC2 DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0 DCD CAN1_RX1_IRQHandler ; CAN1 RX1 DCD CAN1_SCE_IRQHandler ; CAN1 SCE DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 DCD TIM1_BRK_IRQHandler ; TIM1 Break DCD TIM1_UP_IRQHandler ; TIM1 Update DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare DCD TIM2_IRQHandler ; TIM2 DCD TIM3_IRQHandler ; TIM3 DCD TIM4_IRQHandler ; TIM4 DCD I2C1_EV_IRQHandler ; I2C1 Event DCD I2C1_ER_IRQHandler ; I2C1 Error DCD I2C2_EV_IRQHandler ; I2C2 Event DCD I2C2_ER_IRQHandler ; I2C2 Error DCD SPI1_IRQHandler ; SPI1 DCD SPI2_IRQHandler ; SPI2 DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3 DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 DCD RTC_Alarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend DCD TIM8_BRK_IRQHandler ; TIM8 Break DCD TIM8_UP_IRQHandler ; TIM8 Update DCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and Commutation DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare DCD ADC3_IRQHandler ; ADC3 DCD FSMC_IRQHandler ; FSMC DCD SDIO_IRQHandler ; SDIO DCD TIM5_IRQHandler ; TIM5 DCD SPI3_IRQHandler ; SPI3 DCD UART4_IRQHandler ; UART4 DCD UART5_IRQHandler ; UART5 DCD TIM6_IRQHandler ; TIM6 DCD TIM7_IRQHandler ; TIM7 DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1 DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2 DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3 DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5 __Vectors_End __Vectors_Size EQU __Vectors_End - __Vectors AREA |.text|, CODE, READONLY ; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP ; Dummy Exception Handlers (infinite loops which can be modified) NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDP HardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDP MemManage_Handler\ PROC EXPORT MemManage_Handler [WEAK] B . ENDP BusFault_Handler\ PROC EXPORT BusFault_Handler [WEAK] B . ENDP UsageFault_Handler\ PROC EXPORT UsageFault_Handler [WEAK] B . ENDP SVC_Handler PROC EXPORT SVC_Handler [WEAK] B . ENDP DebugMon_Handler\ PROC EXPORT DebugMon_Handler [WEAK] B . ENDP PendSV_Handler PROC EXPORT PendSV_Handler [WEAK] B . ENDP SysTick_Handler PROC EXPORT SysTick_Handler [WEAK] B . ENDP Default_Handler PROC EXPORT WWDG_IRQHandler [WEAK] EXPORT PVD_IRQHandler [WEAK] EXPORT TAMPER_IRQHandler [WEAK] EXPORT RTC_IRQHandler [WEAK] EXPORT FLASH_IRQHandler [WEAK] EXPORT RCC_IRQHandler [WEAK] EXPORT EXTI0_IRQHandler [WEAK] EXPORT EXTI1_IRQHandler [WEAK] EXPORT EXTI2_IRQHandler [WEAK] EXPORT EXTI3_IRQHandler [WEAK] EXPORT EXTI4_IRQHandler [WEAK] EXPORT DMA1_Channel1_IRQHandler [WEAK] EXPORT DMA1_Channel2_IRQHandler [WEAK] EXPORT DMA1_Channel3_IRQHandler [WEAK] EXPORT DMA1_Channel4_IRQHandler [WEAK] EXPORT DMA1_Channel5_IRQHandler [WEAK] EXPORT DMA1_Channel6_IRQHandler [WEAK] EXPORT DMA1_Channel7_IRQHandler [WEAK] EXPORT ADC1_2_IRQHandler [WEAK] EXPORT USB_HP_CAN1_TX_IRQHandler [WEAK] EXPORT USB_LP_CAN1_RX0_IRQHandler [WEAK] EXPORT CAN1_RX1_IRQHandler [WEAK] EXPORT CAN1_SCE_IRQHandler [WEAK] EXPORT EXTI9_5_IRQHandler [WEAK] EXPORT TIM1_BRK_IRQHandler [WEAK] EXPORT TIM1_UP_IRQHandler [WEAK] EXPORT TIM1_TRG_COM_IRQHandler [WEAK] EXPORT TIM1_CC_IRQHandler [WEAK] EXPORT TIM2_IRQHandler [WEAK] EXPORT TIM3_IRQHandler [WEAK] EXPORT TIM4_IRQHandler [WEAK] EXPORT I2C1_EV_IRQHandler [WEAK] EXPORT I2C1_ER_IRQHandler [WEAK] EXPORT I2C2_EV_IRQHandler [WEAK] EXPORT I2C2_ER_IRQHandler [WEAK] EXPORT SPI1_IRQHandler [WEAK] EXPORT SPI2_IRQHandler [WEAK] EXPORT USART1_IRQHandler [WEAK] EXPORT USART2_IRQHandler [WEAK] EXPORT USART3_IRQHandler [WEAK] EXPORT EXTI15_10_IRQHandler [WEAK] EXPORT RTC_Alarm_IRQHandler [WEAK] EXPORT USBWakeUp_IRQHandler [WEAK] EXPORT TIM8_BRK_IRQHandler [WEAK] EXPORT TIM8_UP_IRQHandler [WEAK] EXPORT TIM8_TRG_COM_IRQHandler [WEAK] EXPORT TIM8_CC_IRQHandler [WEAK] EXPORT ADC3_IRQHandler [WEAK] EXPORT FSMC_IRQHandler [WEAK] EXPORT SDIO_IRQHandler [WEAK] EXPORT TIM5_IRQHandler [WEAK] EXPORT SPI3_IRQHandler [WEAK] EXPORT UART4_IRQHandler [WEAK] EXPORT UART5_IRQHandler [WEAK] EXPORT TIM6_IRQHandler [WEAK] EXPORT TIM7_IRQHandler [WEAK] EXPORT DMA2_Channel1_IRQHandler [WEAK] EXPORT DMA2_Channel2_IRQHandler [WEAK] EXPORT DMA2_Channel3_IRQHandler [WEAK] EXPORT DMA2_Channel4_5_IRQHandler [WEAK] WWDG_IRQHandler PVD_IRQHandler TAMPER_IRQHandler RTC_IRQHandler FLASH_IRQHandler RCC_IRQHandler EXTI0_IRQHandler EXTI1_IRQHandler EXTI2_IRQHandler EXTI3_IRQHandler EXTI4_IRQHandler DMA1_Channel1_IRQHandler DMA1_Channel2_IRQHandler DMA1_Channel3_IRQHandler DMA1_Channel4_IRQHandler DMA1_Channel5_IRQHandler DMA1_Channel6_IRQHandler DMA1_Channel7_IRQHandler ADC1_2_IRQHandler USB_HP_CAN1_TX_IRQHandler USB_LP_CAN1_RX0_IRQHandler CAN1_RX1_IRQHandler CAN1_SCE_IRQHandler EXTI9_5_IRQHandler TIM1_BRK_IRQHandler TIM1_UP_IRQHandler TIM1_TRG_COM_IRQHandler TIM1_CC_IRQHandler TIM2_IRQHandler TIM3_IRQHandler TIM4_IRQHandler I2C1_EV_IRQHandler I2C1_ER_IRQHandler I2C2_EV_IRQHandler I2C2_ER_IRQHandler SPI1_IRQHandler SPI2_IRQHandler USART1_IRQHandler USART2_IRQHandler USART3_IRQHandler EXTI15_10_IRQHandler RTC_Alarm_IRQHandler USBWakeUp_IRQHandler TIM8_BRK_IRQHandler TIM8_UP_IRQHandler TIM8_TRG_COM_IRQHandler TIM8_CC_IRQHandler ADC3_IRQHandler FSMC_IRQHandler SDIO_IRQHandler TIM5_IRQHandler SPI3_IRQHandler UART4_IRQHandler UART5_IRQHandler TIM6_IRQHandler TIM7_IRQHandler DMA2_Channel1_IRQHandler DMA2_Channel2_IRQHandler DMA2_Channel3_IRQHandler DMA2_Channel4_5_IRQHandler B . ENDP ALIGN ;******************************************************************************* ; User Stack and Heap initialization ;******************************************************************************* IF :DEF:__MICROLIB EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit ELSE IMPORT __use_two_region_memory EXPORT __user_initial_stackheap __user_initial_stackheap LDR R0, = Heap_Mem LDR R1, =(Stack_Mem + Stack_Size) LDR R2, = (Heap_Mem + Heap_Size) LDR R3, = Stack_Mem BX LR ALIGN ENDIF END ;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****
这段启动代码的作用是:
1.设置堆栈
2.定义中断向量表
3.初始化系统时钟
4.初始化堆栈
5.执行__main,准备c语言的运行环境,初始化程序计数器指针PC指向main,进入c代码
stm32f103是m3的内核,首先来看下存储器映射:

RAM的起始地址是0x20000000。
再来看我们仿真用的stm32f103zf的flash和RAM大小:

到此处我们再来逐步分析启动文件:
一.设置堆栈:
; <h> Stack Configuration ; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp ; <h> Heap Configuration ; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Heap_Size EQU 0x00000200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit PRESERVE8 THUMB
1.定义了一段大小为1KB(0x00000400)的栈空间。
2.__initial_sp:标名,栈顶地址。
看一下.map文件中的一段信息,在.map文件中搜索__initial_sp
.data 0x20000000 Section 192 drv_gpio.o(.data) .data 0x200000c0 Section 68 drv_usart.o(.data) .data 0x20000104 Section 4 system_stm32f1xx.o(.data) .data 0x20000108 Section 4 stm32f1xx_hal.o(.data) .data 0x2000010c Section 4 clock.o(.data) rt_tick 0x2000010c Data 4 clock.o(.data) .data 0x20000110 Section 9 irq.o(.data) rt_interrupt_enter_hook 0x20000110 Data 4 irq.o(.data) rt_interrupt_leave_hook 0x20000114 Data 4 irq.o(.data) .data 0x2000011c Section 12 kservice.o(.data) __rt_errno 0x2000011c Data 4 kservice.o(.data) _console_device 0x20000120 Data 4 kservice.o(.data) .data 0x20000128 Section 32 mem.o(.data) rt_malloc_hook 0x20000128 Data 4 mem.o(.data) rt_free_hook 0x2000012c Data 4 mem.o(.data) heap_ptr 0x20000130 Data 4 mem.o(.data) heap_end 0x20000134 Data 4 mem.o(.data) lfree 0x20000138 Data 4 mem.o(.data) mem_size_aligned 0x2000013c Data 4 mem.o(.data) used_mem 0x20000140 Data 4 mem.o(.data) max_mem 0x20000144 Data 4 mem.o(.data) .data 0x20000148 Section 8 mempool.o(.data) rt_mp_alloc_hook 0x20000148 Data 4 mempool.o(.data) rt_mp_free_hook 0x2000014c Data 4 mempool.o(.data) .data 0x20000150 Section 180 object.o(.data) rt_object_container 0x20000150 Data 160 object.o(.data) rt_object_attach_hook 0x200001f0 Data 4 object.o(.data) rt_object_detach_hook 0x200001f4 Data 4 object.o(.data) .data 0x20000204 Section 28 scheduler.o(.data) rt_scheduler_lock_nest 0x20000204 Data 2 scheduler.o(.data) rt_scheduler_hook 0x2000021c Data 4 scheduler.o(.data) .data 0x20000220 Section 4 signal.o(.data) _rt_siginfo_pool 0x20000220 Data 4 signal.o(.data) .data 0x20000224 Section 16 timer.o(.data) rt_timer_list 0x20000224 Data 8 timer.o(.data) rt_timer_timeout_hook 0x2000022c Data 4 timer.o(.data) random_nr 0x20000230 Data 4 timer.o(.data) .data 0x20000234 Section 12 thread.o(.data) rt_thread_suspend_hook 0x20000234 Data 4 thread.o(.data) rt_thread_resume_hook 0x20000238 Data 4 thread.o(.data) rt_thread_inited_hook 0x2000023c Data 4 thread.o(.data) .data 0x20000240 Section 16 cpuport.o(.data) rt_exception_hook 0x2000024c Data 4 cpuport.o(.data) .data 0x20000250 Section 4 shell.o(.data) .data 0x20000254 Section 16 symbol.o(.data) .data 0x20000264 Section 8 idlehook_sample.o(.data) tid 0x20000264 Data 4 idlehook_sample.o(.data) hook_times 0x20000268 Data 4 idlehook_sample.o(.data) .data 0x2000026c Section 4 interrupt_sample.o(.data) cnt 0x2000026c Data 4 interrupt_sample.o(.data) .data 0x20000270 Section 39 mailbox_sample.o(.data) mb_str1 0x20000270 Data 12 mailbox_sample.o(.data) mb_str2 0x2000027c Data 22 mailbox_sample.o(.data) mb_str3 0x20000292 Data 5 mailbox_sample.o(.data) .data 0x20000298 Section 8 memp_sample.o(.data) tid1 0x20000298 Data 4 memp_sample.o(.data) tid2 0x2000029c Data 4 memp_sample.o(.data) .data 0x200002a0 Section 6 mutex_sample.o(.data) dynamic_mutex 0x200002a0 Data 4 mutex_sample.o(.data) number1 0x200002a4 Data 1 mutex_sample.o(.data) number2 0x200002a5 Data 1 mutex_sample.o(.data) .data 0x200002a8 Section 16 priority_inversion.o(.data) tid1 0x200002a8 Data 4 priority_inversion.o(.data) tid2 0x200002ac Data 4 priority_inversion.o(.data) tid3 0x200002b0 Data 4 priority_inversion.o(.data) mutex 0x200002b4 Data 4 priority_inversion.o(.data) .data 0x200002b8 Section 16 producer_consumer.o(.data) set 0x200002b8 Data 4 producer_consumer.o(.data) get 0x200002bc Data 4 producer_consumer.o(.data) producer_tid 0x200002c0 Data 4 producer_consumer.o(.data) consumer_tid 0x200002c4 Data 4 producer_consumer.o(.data) .data 0x200002c8 Section 16 scheduler_hook.o(.data) tid1 0x200002d0 Data 4 scheduler_hook.o(.data) tid2 0x200002d4 Data 4 scheduler_hook.o(.data) .data 0x200002d8 Section 13 semaphore_sample.o(.data) dynamic_sem 0x200002d8 Data 4 semaphore_sample.o(.data) count 0x200002dc Data 1 semaphore_sample.o(.data) result 0x200002e0 Data 4 semaphore_sample.o(.data) number 0x200002e4 Data 1 semaphore_sample.o(.data) .data 0x200002e8 Section 4 signal_sample.o(.data) tid1 0x200002e8 Data 4 signal_sample.o(.data) .data 0x200002ec Section 4 thread_sample.o(.data) tid1 0x200002ec Data 4 thread_sample.o(.data) .data 0x200002f0 Section 12 timer_sample.o(.data) timer1 0x200002f0 Data 4 timer_sample.o(.data) timer2 0x200002f4 Data 4 timer_sample.o(.data) cnt 0x200002f8 Data 4 timer_sample.o(.data) .bss 0x200002fc Section 84 drv_usart.o(.bss) .bss 0x20000350 Section 420 idle.o(.bss) idle 0x20000350 Data 148 idle.o(.bss) rt_thread_stack 0x200003e4 Data 256 idle.o(.bss) idle_hook_list 0x200004e4 Data 16 idle.o(.bss) .bss 0x200004f4 Section 128 kservice.o(.bss) rt_log_buf 0x200004f4 Data 128 kservice.o(.bss) .bss 0x20000574 Section 32 mem.o(.bss) heap_sem 0x20000574 Data 32 mem.o(.bss) .bss 0x20000594 Section 256 scheduler.o(.bss) .bss 0x20000694 Section 68 pin.o(.bss) _hw_pin 0x20000694 Data 68 pin.o(.bss) .bss 0x200006d8 Section 129 shell.o(.bss) finsh_prompt 0x200006d8 Data 129 shell.o(.bss) .bss 0x2000075c Section 2376 event_sample.o(.bss) event 0x2000075c Data 32 event_sample.o(.bss) thread1_stack 0x2000077c Data 1024 event_sample.o(.bss) thread1 0x20000b7c Data 148 event_sample.o(.bss) thread2_stack 0x20000c10 Data 1024 event_sample.o(.bss) thread2 0x20001010 Data 148 event_sample.o(.bss) .bss 0x200010a4 Section 2520 mailbox_sample.o(.bss) mb 0x200010a4 Data 48 mailbox_sample.o(.bss) mb_pool 0x200010d4 Data 128 mailbox_sample.o(.bss) thread1_stack 0x20001154 Data 1024 mailbox_sample.o(.bss) thread1 0x20001554 Data 148 mailbox_sample.o(.bss) thread2_stack 0x200015e8 Data 1024 mailbox_sample.o(.bss) thread2 0x200019e8 Data 148 mailbox_sample.o(.bss) .bss 0x20001a7c Section 4352 memp_sample.o(.bss) ptr 0x20001a7c Data 200 memp_sample.o(.bss) mempool 0x20001b44 Data 4096 memp_sample.o(.bss) mp 0x20002b44 Data 56 memp_sample.o(.bss) .bss 0x20002b7c Section 4444 msgq_sample.o(.bss) mq 0x20002b7c Data 52 msgq_sample.o(.bss) msg_pool 0x20002bb0 Data 2048 msgq_sample.o(.bss) thread1_stack 0x200033b0 Data 1024 msgq_sample.o(.bss) thread1 0x200037b0 Data 148 msgq_sample.o(.bss) thread2_stack 0x20003844 Data 1024 msgq_sample.o(.bss) thread2 0x20003c44 Data 148 msgq_sample.o(.bss) .bss 0x20003cd8 Section 2344 mutex_sample.o(.bss) thread1_stack 0x20003cd8 Data 1024 mutex_sample.o(.bss) thread1 0x200040d8 Data 148 mutex_sample.o(.bss) thread2_stack 0x2000416c Data 1024 mutex_sample.o(.bss) thread2 0x2000456c Data 148 mutex_sample.o(.bss) .bss 0x20004600 Section 116 producer_consumer.o(.bss) .bss 0x20004674 Section 2344 semaphore_sample.o(.bss) thread1_stack 0x20004674 Data 1024 semaphore_sample.o(.bss) thread1 0x20004a74 Data 148 semaphore_sample.o(.bss) thread2_stack 0x20004b08 Data 1024 semaphore_sample.o(.bss) thread2 0x20004f08 Data 148 semaphore_sample.o(.bss) .bss 0x20004f9c Section 1172 thread_sample.o(.bss) thread2_stack 0x20004f9c Data 1024 thread_sample.o(.bss) thread2 0x2000539c Data 148 thread_sample.o(.bss) STACK 0x20005430 Section 1024 startup_stm32f103xe.o(STACK)
pin_irq_hdr_tab 0x20000000 Data 192 drv_gpio.o(.data) uart1 0x200000c0 Data 68 drv_usart.o(.data) SystemCoreClock 0x20000104 Data 4 system_stm32f1xx.o(.data) uwTick 0x20000108 Data 4 stm32f1xx_hal.o(.data) rt_interrupt_nest 0x20000118 Data 1 irq.o(.data) rt_assert_hook 0x20000124 Data 4 kservice.o(.data) rt_object_trytake_hook 0x200001f8 Data 4 object.o(.data) rt_object_take_hook 0x200001fc Data 4 object.o(.data) rt_object_put_hook 0x20000200 Data 4 object.o(.data) rt_current_thread 0x20000208 Data 4 scheduler.o(.data) rt_current_priority 0x2000020c Data 1 scheduler.o(.data) rt_thread_ready_priority_group 0x20000210 Data 4 scheduler.o(.data) rt_thread_defunct 0x20000214 Data 8 scheduler.o(.data) rt_interrupt_from_thread 0x20000240 Data 4 cpuport.o(.data) rt_interrupt_to_thread 0x20000244 Data 4 cpuport.o(.data) rt_thread_switch_interrupt_flag 0x20000248 Data 4 cpuport.o(.data) shell 0x20000250 Data 4 shell.o(.data) _syscall_table_begin 0x20000254 Data 4 symbol.o(.data) _syscall_table_end 0x20000258 Data 4 symbol.o(.data) _sysvar_table_begin 0x2000025c Data 4 symbol.o(.data) _sysvar_table_end 0x20000260 Data 4 symbol.o(.data) count 0x200002c8 Data 8 scheduler_hook.o(.data) serial1 0x200002fc Data 84 drv_usart.o(.bss) rt_thread_priority_table 0x20000594 Data 256 scheduler.o(.bss) array 0x20004600 Data 20 producer_consumer.o(.bss) sem_lock 0x20004614 Data 32 producer_consumer.o(.bss) sem_empty 0x20004634 Data 32 producer_consumer.o(.bss) sem_full 0x20004654 Data 32 producer_consumer.o(.bss) Image$$RW_IRAM1$$ZI$$Limit 0x20005830 Number 0 anon$$obj.o ABSOLUTE __initial_sp 0x20005830 Data 0 startup_stm32f103xe.o(STACK)
从map文件中可以看到栈的起始地址(0x20005430)和大小(1024)以及栈顶地址(0x20005830):


画图示意一下:

栈的大小我们设置的为1k,栈底地址为0x20005430,那么__initial_sp为什么是0x20005830而不是0x2000582F呢?这个可以在《Cortex M3权威指南》中找到答案:

3.开辟堆空间
堆大小:0.5K
堆的基地址:__heap_base
堆的顶地址:__heap_limit

在map文件中找HEAP发现被优化掉了:

添加一段代码,把堆用起来防止被优化掉:

如愿以偿的得到了堆:


画图示意一下:

4.向量表
异常类型:
Cortex-M3在内核水平上搭载了一个异常相应系统,支持位数众多的系统异常和外部中断。编号为1-15的对应系统异常,大于等于16的则全是外部中断。除了个别异常的优先级被定死外,其它异常的优先级都是可编程的(所有能打断正常执行流的事件都称为异常)
系统异常清单:

外部中断清单:

关于异常相关知识参考《Cortex M3权威指南》。
当发生了异常并且要相应它时,CM3需要定位其处理例程的入口地址。这些入口地址存储在所谓的"(异常)向量表中"。缺省情况下,CM3认为该表位于零地址处,且各向量占4字节,因此每个表项占用4字节:

由以上的信息我们结合汇编代码来看向量表其实就是一个32位整数数组,每个下标对应了一种异常,对应的元素值就是异常服务例程的入口地址。其中下标0不是异常服务例程的入口地址,而是复位后的MSP的初值__initial_sp(实验例程中从map文件中查看当前值为0x20005A38),向量表从FLASH的0地址开始放置,除了地址0存放的是MSP初始值之外,从代码上看,其他元素都是中断服务函数的函数名,函数名就是地址。
; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler ; External Interrupts DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; Tamper DCD RTC_IRQHandler ; RTC DCD FLASH_IRQHandler ; Flash DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line 0 ;省略部分代码 __Vectors_End __Vectors_Size EQU __Vectors_End - __Vectors AREA |.text|, CODE, READONLY
仿真将例程,可以看到寄存器R13的值被初始化为栈顶地址0x20005A38,向量表中存放了各个异常服务例程入口地址。
有人可能会有疑问:为什么向量表中的值是0x080041B1(也就是奇数),而实际的服务函数的地址是0x080041B0呢?
这个问题在《Cortex M3权威指南》中有详细说明。

复位程序,默认商店复位后执行的程序

我们把Run to main()勾掉,点击仿真,可以看出刚开始执行时的情况->内核停止在Reset_Handler上:


在Reset_Handler中,程序最后调用了__main,需要注意的是这个函数并不是main函数的别名或者编译之后的名字,__main和main是两个完全不同的函数,我们确实在工程中找不到__main函数的源代码,因为这个函数是链接器自动创建的:

__main()函数中有两个函数:

__scatterload():

__rt_entry():初始化堆栈、C库函数初始化,调用各种初始化函数最终调用用户层的main(),以下列出__rt_entry()可以调用的函数(按调用顺序列出)。
1. _platform_pre_stackheap_init:标准C库不提供,用户自己定义,__rt_entry在设置堆栈和堆之前调用此函数
2. __user_setup_stackheap or setup the Stack Pointer (SP) by another method:
3. _platform_post_stackheap_init
4. __rt_lib_init
5. _platform_post_lib_init
6. main()
7. exit()
_platform_*函数不是标准C库的一部分,如果你定义它们,__rt_enry会调用它们。
main()函数是用户级应用程序入口点,寄存器r0和r1包含main()的参数。如果main()返回,则将其返回值传递给exit()并退出应用程序。
我们在c语言标准中可以看到对main函数的标准定义:

所以标准中是没有void main(void){}形式的定义的。
__rt_enry还负责设置堆栈和堆。但是设置堆栈和堆取决于用户指定的方法。

__user_initial_stackheap:这个函数使你设置并返回初始堆栈和堆的位置,C库不提供此函数,你可以自定义它,然后被__rt_entry调用。
我们在启动文件中可以看到此函数定义:
;******************************************************************************* ; User Stack and Heap initialization ;******************************************************************************* IF :DEF:__MICROLIB;如果使用了微库(MicroLib),直接导出堆栈地址符号 EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit ELSE IMPORT __use_two_region_memory;导入外部程序并执行 EXPORT __user_initial_stackheap;导出子程序符号给外部程序调用 __user_initial_stackheap LDR R0, = Heap_Mem LDR R1, =(Stack_Mem + Stack_Size) LDR R2, = (Heap_Mem + Heap_Size) LDR R3, = Stack_Mem BX LR ALIGN ENDIF END
__rt_lib_init

此函数初始化了C库子系统。初始化了引用的库函数、语言环境。必要时为main()设置argc和argv。在启动时__rt_entry必调此函数。
以下列出__rt_lib_init调用的函数:
1. _fp_init
2. _init_alloc
3. _rand_init
4. _get_lc_collate
5. _get_lc_ctype
6. _get_lc_monetary
7. _get_lc_numeric
8. _get_lc_time
9. _atexit_init
10. _signal_init
11. _fp_trap_init
12. _clock_init
13. _getenv_init
14. _initio
15. _ARM_get_argv
16._alloca_initialize
17. _ARM_exceptions_init
18. __cpp_initialize__aeabi_
各个函数具体看官方文档。
总结:通过以上的分析,我们知道了CM3复位之后通过向量表调到Reset_Handler中断服务子程序中调用库函数__main()->__rt_entry->main()这么一个流程。
2.2 rtthread对main()函数的扩展操作
components.c中的代码:
$Sub$$main()调用rtthread_startup()函数。rtthread_startup()函数是RT-Thread规定的统一入口点。

首先来看下rt_hw_interrupt_disable()和rt_hw_interrupt_enable(),他们的定义在context_rvds.S中:
;/* ; * rt_base_t rt_hw_interrupt_disable(); ; */ rt_hw_interrupt_disable PROC EXPORT rt_hw_interrupt_disable MRS r0, PRIMASK;读取PRIMASK到r0 CPSID I;关中断,PRIMASK=1 BX LR ENDP ;/* ; * void rt_hw_interrupt_enable(rt_base_t level); ; */ rt_hw_interrupt_enable PROC EXPORT rt_hw_interrupt_enable MSR PRIMASK, r0;写r0到PRIMASK BX LR ENDP
特殊功能寄存器组
Cortex-M3中的特殊功能寄存器包括:
1.程序状态寄存器组(PSRs或xPSR)
2.中断屏蔽寄存器组(PRIMASK,FAULTMASK,BASEPRI):用于控制异常的使能和除能。
3.控制寄存器(CONTROL)

对于时间-关键任务而言,PRIMASK和BASEPRI对于暂时关闭中断是非常重要的。为了快速开关中断,CM3还设置了一条CPS指令:

仿真来看一下程序启动关闭中断:

RT-Thread的启动流程:
int rtthread_startup(void) { rt_hw_interrupt_disable(); /* board level initalization * 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(); #ifdef RT_USING_SIGNALS /* signal system initialization */ rt_system_signal_init(); #endif /* 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; }
1.初始化系统相关硬件
2.初始化系统内核对象
3.初始化系统设备
4.初始化各个应用线程,启动调度器
RT-Thread将main函数作为用户代码入口,只需要在main函数里添加自己的应用即可:

main函数在main_thread_entry中调用:

跑马灯的例子:
在UART#1中输入msh命令:led+回车就可以运行起来了:

事已至此呢,跑马灯例程成功运行。上手成功

浙公网安备 33010602011771号