启动STM32F4所需的最有效的方式/最少的代码是什么?来自ST的启动文件似乎包含许多不必要的代码。
启动STM32F4所需的最有效的方式/最少的代码是什么?来自ST的启动文件似乎包含许多不必要的代码。
Answers:
您可能不想使用供应商提供的启动代码。很少有人会这样做:
创建更高效或更轻松的代码。对供应商代码有特殊要求。您想知道东西是如何工作的。您想在许多不同的MCU中使用某种通用代码。您需要对流程进行全面控制。等等..
以下内容仅适用于C程序(无C ++,异常等)和Cortex M微控制器(与品牌/型号无关)。我还假定您使用GCC,尽管与其他编译器可能没有差异或几乎没有差异。最后,我使用newlib。
首先要做的是创建一个链接描述文件。您必须告诉编译器如何在内存中排列内容。我不会详细介绍链接描述文件,因为它本身就是一个主题。
/*
* Linker script.
*/
/*
* Set the output format. Currently set for Cortex M architectures,
* may need to be modified if the library has to support other MCUs,
* or completelly removed.
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/*
* Just refering a function included in the vector table, and that
* it is defined in the same file with it, so the vector table does
* not get optimized out.
*/
EXTERN(Reset_Handler)
/*
* ST32F103x8 memory setup.
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64k
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20k
}
/*
* Necessary group so the newlib stubs provided in the library,
* will correctly be linked with the appropriate newlib functions,
* and not optimized out, giving errors for undefined symbols.
* This way the libraries can be fed to the linker in any order.
*/
GROUP(
libgcc.a
libg.a
libc.a
libm.a
libnosys.a
)
/*
* Stack start pointer. Here set to the end of the stack
* memory, as in most architectures (including all the
* new ARM ones), the stack starts from the maximum address
* and grows towards the bottom.
*/
__stack = ORIGIN(RAM) + LENGTH(RAM);
/*
* Programm entry function. Used by the debugger only.
*/
ENTRY(_start)
/*
* Memory Allocation Sections
*/
SECTIONS
{
/*
* For normal programs should evaluate to 0, for placing the vector
* table at the correct position.
*/
. = ORIGIN(FLASH);
/*
* First link the vector table.
*/
.vectors : ALIGN(4)
{
FILL(0xFF)
__vectors_start__ = ABSOLUTE(.);
KEEP(*(.vectors))
*(.after_vectors .after_vectors.*)
} > FLASH
/*
* Start of text.
*/
_text = .;
/*
* Text section
*/
.text : ALIGN(4)
{
*(.text)
*(.text.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
} > FLASH
/*
* Arm section unwinding.
* If removed may cause random crashes.
*/
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
/*
* Arm stack unwinding.
* If removed may cause random crashes.
*/
.ARM.exidx :
{
__exidx_start = .;
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end = .;
} > FLASH
/*
* Section used by C++ to access eh_frame.
* Generaly not used, but it doesn't harm to be there.
*/
.eh_frame_hdr :
{
*(.eh_frame_hdr)
} > FLASH
/*
* Stack unwinding code.
* Generaly not used, but it doesn't harm to be there.
*/
.eh_frame : ONLY_IF_RO
{
*(.eh_frame)
} > FLASH
/*
* Read-only data. Consts should also be here.
*/
.rodata : ALIGN(4)
{
. = ALIGN(4);
__rodata_start__ = .;
*(.rodata)
*(.rodata.*)
. = ALIGN(4);
__rodata_end__ = .;
} > FLASH
/*
* End of text.
*/
_etext = .;
/*
* Data section.
*/
.data : ALIGN(4)
{
FILL(0xFF)
. = ALIGN(4);
PROVIDE(__textdata__ = LOADADDR(.data));
PROVIDE(__data_start__ = .);
*(.data)
*(.data.*)
*(.ramtext)
. = ALIGN(4);
PROVIDE(__data_end__ = .);
} > RAM AT > FLASH
/*
* BSS section.
*/
.bss (NOLOAD) : ALIGN(4)
{
. = ALIGN(4);
PROVIDE(_bss_start = .);
__bss_start__ = .;
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
PROVIDE(_bss_end = .);
__bss_end__ = .;
PROVIDE(end = .);
} > RAM
/*
* Non-initialized variables section.
* A variable should be explicitly placed
* here, aiming in speeding-up boot time.
*/
.noinit (NOLOAD) : ALIGN(4)
{
__noinit_start__ = .;
*(.noinit .noinit.*)
. = ALIGN(4) ;
__noinit_end__ = .;
} > RAM
/*
* Heap section.
*/
.heap (NOLOAD) :
{
. = ALIGN(4);
__heap_start__ = .;
__heap_base__ = .;
. = ORIGIN(HEAP_RAM) + LENGTH(HEAP_RAM);
__heap_end__ = .;
} > RAM
}
您可以直接使用提供的链接描述文件。注意事项:
这是我使用的链接描述文件的简化版本。在精简过程中,我可能会向代码引入错误,请仔细检查。
由于我将其用于除您以外的其他MCU,因此您必须更改MEMORY布局以适合您自己的布局。
您可能需要更改以下链接的库才能与您自己的库链接。在这里,它链接到newlib。
您必须在代码中包含向量表。这只是一个功能指针的查询表,如果发生中断,硬件将自动跳转到该表。这在C语言中相当容易做到。
看一下以下文件。这是用于STM32F103C8 MCU,但是很容易更改您的需求。
#include "stm32f10x.h"
#include "debug.h"
//Start-up code.
extern void __attribute__((noreturn, weak)) _start (void);
// Default interrupt handler
void __attribute__ ((section(".after_vectors"), noreturn)) __Default_Handler(void);
// Reset handler
void __attribute__ ((section(".after_vectors"), noreturn)) Reset_Handler (void);
/** Non-maskable interrupt (RCC clock security system) */
void NMI_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** All class of fault */
void HardFault_Handler(void) __attribute__ ((interrupt, weak));
/** Memory management */
void MemManage_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** Pre-fetch fault, memory access fault */
void BusFault_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** Undefined instruction or illegal state */
void UsageFault_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** System service call via SWI instruction */
void SVC_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** Debug monitor */
void DebugMon_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** Pendable request for system service */
void PendSV_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** System tick timer */
void SysTick_Handler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** Window watchdog interrupt */
void WWDG_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** PVD through EXTI line detection interrupt */
void PVD_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** Tamper interrupt */
void TAMPER_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** RTC global interrupt */
void RTC_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** Flash global interrupt */
void FLASH_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** RCC global interrupt */
void RCC_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** EXTI Line0 interrupt */
void EXTI0_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** EXTI Line1 interrupt */
void EXTI1_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** EXTI Line2 interrupt */
void EXTI2_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** EXTI Line3 interrupt */
void EXTI3_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** EXTI Line4 interrupt */
void EXTI4_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA1 Channel1 global interrupt */
void DMA1_Channel1_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA1 Channel2 global interrupt */
void DMA1_Channel2_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA1 Channel3 global interrupt */
void DMA1_Channel3_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA1 Channel4 global interrupt */
void DMA1_Channel4_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA1 Channel5 global interrupt */
void DMA1_Channel5_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA1 Channel6 global interrupt */
void DMA1_Channel6_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA1 Channel7 global interrupt */
void DMA1_Channel7_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** ADC1 and ADC2 global interrupt */
void ADC1_2_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** USB high priority or CAN TX interrupts */
void USB_HP_CAN_TX_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** USB low priority or CAN RX0 interrupts */
void USB_LP_CAN_RX0_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** CAN RX1 interrupt */
void CAN_RX1_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** CAN SCE interrupt */
void CAN_SCE_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** EXTI Line[9:5] interrupts */
void EXTI9_5_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM1 break interrupt */
void TIM1_BRK_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM1 update interrupt */
void TIM1_UP_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM1 trigger and commutation interrupts */
void TIM1_TRG_COM_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM1 capture compare interrupt */
void TIM1_CC_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM2 global interrupt */
void TIM2_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM3 global interrupt */
void TIM3_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM4 global interrupt */
void TIM4_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** I2C1 event interrupt */
void I2C1_EV_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** I2C1 error interrupt */
void I2C1_ER_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** I2C2 event interrupt */
void I2C2_EV_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** I2C2 error interrupt */
void I2C2_ER_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** SPI1 global interrupt */
void SPI1_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** SPI2 global interrupt */
void SPI2_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** USART1 global interrupt */
void USART1_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** USART2 global interrupt */
void USART2_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** USART3 global interrupt */
void USART3_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** EXTI Line[15:10] interrupts */
void EXTI15_10_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** RTC alarm through EXTI line interrupt */
void RTCAlarm_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** USB wakeup from suspend through EXTI line interrupt */
void USBWakeup_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM8 break interrupt */
void TIM8_BRK_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM8 update interrupt */
void TIM8_UP_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM8 trigger and commutation interrupts */
void TIM8_TRG_COM_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM8 capture compare interrupt */
void TIM8_CC_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** ADC3 global interrupt */
void ADC3_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** FSMC global interrupt */
void FSMC_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** SDIO global interrupt */
void SDIO_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM5 global interrupt */
void TIM5_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** SPI3 global interrupt */
void SPI3_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** UART4 global interrupt */
void UART4_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** UART5 global interrupt */
void UART5_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM6 global interrupt */
void TIM6_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** TIM7 global interrupt */
void TIM7_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA2 Channel1 global interrupt */
void DMA2_Channel1_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA2 Channel2 global interrupt */
void DMA2_Channel2_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA2 Channel3 global interrupt */
void DMA2_Channel3_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
/** DMA2 Channel4 and DMA2 Channel5 global interrupts */
void DMA2_Channel4_5_IRQHandler(void) __attribute__ ((interrupt, weak, alias("__Default_Handler")));
// Stack start variable, needed in the vector table.
extern unsigned int __stack;
// Typedef for the vector table entries.
typedef void (* const pHandler)(void);
/** STM32F103 Vector Table */
__attribute__ ((section(".vectors"), used)) pHandler vectors[] =
{
(pHandler) &__stack, // The initial stack pointer
Reset_Handler, // The reset handler
NMI_Handler, // The NMI handler
HardFault_Handler, // The hard fault handler
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
MemManage_Handler, // The MPU fault handler
BusFault_Handler,// The bus fault handler
UsageFault_Handler,// The usage fault handler
#else
0, 0, 0, // Reserved
#endif
0, // Reserved
0, // Reserved
0, // Reserved
0, // Reserved
SVC_Handler, // SVCall handler
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
DebugMon_Handler, // Debug monitor handler
#else
0, // Reserved
#endif
0, // Reserved
PendSV_Handler, // The PendSV handler
SysTick_Handler, // The SysTick handler
// ----------------------------------------------------------------------
WWDG_IRQHandler, // Window watchdog interrupt
PVD_IRQHandler, // PVD through EXTI line detection interrupt
TAMPER_IRQHandler, // Tamper interrupt
RTC_IRQHandler, // RTC global interrupt
FLASH_IRQHandler, // Flash global interrupt
RCC_IRQHandler, // RCC global interrupt
EXTI0_IRQHandler, // EXTI Line0 interrupt
EXTI1_IRQHandler, // EXTI Line1 interrupt
EXTI2_IRQHandler, // EXTI Line2 interrupt
EXTI3_IRQHandler, // EXTI Line3 interrupt
EXTI4_IRQHandler, // EXTI Line4 interrupt
DMA1_Channel1_IRQHandler, // DMA1 Channel1 global interrupt
DMA1_Channel2_IRQHandler, // DMA1 Channel2 global interrupt
DMA1_Channel3_IRQHandler, // DMA1 Channel3 global interrupt
DMA1_Channel4_IRQHandler, // DMA1 Channel4 global interrupt
DMA1_Channel5_IRQHandler, // DMA1 Channel5 global interrupt
DMA1_Channel6_IRQHandler, // DMA1 Channel6 global interrupt
DMA1_Channel7_IRQHandler, // DMA1 Channel7 global interrupt
ADC1_2_IRQHandler, // ADC1 and ADC2 global interrupt
USB_HP_CAN_TX_IRQHandler, // USB high priority or CAN TX interrupts
USB_LP_CAN_RX0_IRQHandler, // USB low priority or CAN RX0 interrupts
CAN_RX1_IRQHandler, // CAN RX1 interrupt
CAN_SCE_IRQHandler, // CAN SCE interrupt
EXTI9_5_IRQHandler, // EXTI Line[9:5] interrupts
TIM1_BRK_IRQHandler, // TIM1 break interrupt
TIM1_UP_IRQHandler, // TIM1 update interrupt
TIM1_TRG_COM_IRQHandler, // TIM1 trigger and commutation interrupts
TIM1_CC_IRQHandler, // TIM1 capture compare interrupt
TIM2_IRQHandler, // TIM2 global interrupt
TIM3_IRQHandler, // TIM3 global interrupt
TIM4_IRQHandler, // TIM4 global interrupt
I2C1_EV_IRQHandler, // I2C1 event interrupt
I2C1_ER_IRQHandler, // I2C1 error interrupt
I2C2_EV_IRQHandler, // I2C2 event interrupt
I2C2_ER_IRQHandler, // I2C2 error interrupt
SPI1_IRQHandler, // SPI1 global interrupt
SPI2_IRQHandler, // SPI2 global interrupt
USART1_IRQHandler, // USART1 global interrupt
USART2_IRQHandler, // USART2 global interrupt
USART3_IRQHandler, // USART3 global interrupt
EXTI15_10_IRQHandler, // EXTI Line[15:10] interrupts
RTCAlarm_IRQHandler, // RTC alarm through EXTI line interrupt
USBWakeup_IRQHandler, // USB wakeup from suspend through EXTI line interrupt
TIM8_BRK_IRQHandler, // TIM8 break interrupt
TIM8_UP_IRQHandler, // TIM8 update interrupt
TIM8_TRG_COM_IRQHandler, // TIM8 trigger and commutation interrupts
TIM8_CC_IRQHandler, // TIM8 capture compare interrupt
ADC3_IRQHandler, // ADC3 global interrupt
FSMC_IRQHandler, // FSMC global interrupt
SDIO_IRQHandler, // SDIO global interrupt
TIM5_IRQHandler, // TIM5 global interrupt
SPI3_IRQHandler, // SPI3 global interrupt
UART4_IRQHandler, // UART4 global interrupt
UART5_IRQHandler, // UART5 global interrupt
TIM6_IRQHandler, // TIM6 global interrupt
TIM7_IRQHandler, // TIM7 global interrupt
DMA2_Channel1_IRQHandler, // DMA2 Channel1 global interrupt
DMA2_Channel2_IRQHandler, // DMA2 Channel2 global interrupt
DMA2_Channel3_IRQHandler, // DMA2 Channel3 global interrupt
DMA2_Channel4_5_IRQHandler // DMA2 Channel4 and DMA2 Channel5 global interrupts
};
/** Default exception/interrupt handler */
void __attribute__ ((section(".after_vectors"), noreturn)) __Default_Handler(void)
{
#ifdef DEBUG
while (1);
#else
NVIC_SystemReset();
while(1);
#endif
}
/** Reset handler */
void __attribute__ ((section(".after_vectors"), noreturn)) Reset_Handler(void)
{
_start();
while(1);
}
这是怎么回事。-首先,我声明了_start函数,以便可以在下面使用它。-我为所有中断声明一个默认处理程序,并为复位处理程序-我声明了我的MCU所需的所有中断处理程序。请注意,这些函数只是默认处理程序的别名,即,当调用它们中的任何一个时,将改为调用默认处理程序。同样,它们被声明为周,因此您可以通过代码覆盖它们。如果需要任何处理程序,则可以在代码中重新声明它,然后将链接您的代码。如果您不需要它们,则只需一个默认值即可,而无需执行任何操作。默认处理程序的结构应这样,如果您的应用程序需要一个处理程序但您没有实现它,它将帮助您调试代码,或者在野外恢复系统。-我得到了链接描述文件中声明的__stack符号。向量表中需要它。-我定义表格本身。请注意,第一个条目是指向堆栈开始的指针,其他条目是指向处理程序的指针。-最后,我为默认处理程序和重置处理程序提供了一个简单的实现。请注意,重置处理程序是在重置后调用的处理程序,它调用启动代码。
请记住,绝对需要向量表中的属性((section())),因此链接器会将表放置在正确的位置(通常地址为0x00000000)。
需要对上述文件进行哪些修改。
由于我使用newlib,因此它需要您提供某些功能的实现。您可以实现printf,scanf等,但不是必需的。我个人仅提供以下内容:
_sbrk是malloc所需的。(无需修改)
#include <sys/types.h>
#include <errno.h>
caddr_t __attribute__((used)) _sbrk(int incr)
{
extern char __heap_start__; // Defined by the linker.
extern char __heap_end__; // Defined by the linker.
static char* current_heap_end;
char* current_block_address;
if (current_heap_end == 0)
{
current_heap_end = &__heap_start__;
}
current_block_address = current_heap_end;
// Need to align heap to word boundary, else will get
// hard faults on Cortex-M0. So we assume that heap starts on
// word boundary, hence make sure we always add a multiple of
// 4 to it.
incr = (incr + 3) & (~3); // align value to 4
if (current_heap_end + incr > &__heap_end__)
{
// Heap has overflowed
errno = ENOMEM;
return (caddr_t) - 1;
}
current_heap_end += incr;
return (caddr_t) current_block_address;
}
_exit,这不是必需的,但我喜欢这个主意。(您可能只需要修改CMSIS包含)。
#include <sys/types.h>
#include <errno.h>
#include "stm32f10x.h"
void __attribute__((noreturn, used)) _exit(int code)
{
(void) code;
NVIC_SystemReset();
while(1);
}
终于启动代码了!
#include <stdint.h>
#include "stm32f10x.h"
#include "gpio.h"
#include "flash.h"
/** Main program entry point. */
extern int main(void);
/** Exit system call. */
extern void _exit(int code);
/** Initializes the data section. */
static void __attribute__((always_inline)) __initialize_data (unsigned int* from, unsigned int* region_begin, unsigned int* region_end);
/** Initializes the BSS section. */
static void __attribute__((always_inline)) __initialize_bss (unsigned int* region_begin, unsigned int* region_end);
/** Start-up code. */
void __attribute__ ((section(".after_vectors"), noreturn, used)) _start(void);
void _start (void)
{
//Before switching on the main oscillator and the PLL,
//and getting to higher and dangerous frequencies,
//configuration of the flash controller is necessary.
//Enable the flash prefetch buffer. Can be achieved when CCLK
//is lower than 24MHz.
Flash_prefetchBuffer(1);
//Set latency to 2 clock cycles. Necessary for setting the clock
//to the maximum 72MHz.
Flash_setLatency(2);
// Initialize hardware right after configuring flash, to switch
//clock to higher frequency and have the rest of the
//initializations run faster.
SystemInit();
// Copy the DATA segment from Flash to RAM (inlined).
__initialize_data(&__textdata__, &__data_start__, &__data_end__);
// Zero fill the BSS section (inlined).
__initialize_bss(&__bss_start__, &__bss_end__);
//Core is running normally, RAM and FLASH are initialized
//properly, now the system must be fully functional.
//Update the SystemCoreClock variable.
SystemCoreClockUpdate();
// Call the main entry point, and save the exit code.
int code = main();
//Main should never return. If it does, let the system exit gracefully.
_exit (code);
// Should never reach this, _exit() should have already
// performed a reset.
while(1);
}
static inline void __initialize_data (unsigned int* from, unsigned int* region_begin, unsigned int* region_end)
{
// Iterate and copy word by word.
// It is assumed that the pointers are word aligned.
unsigned int *p = region_begin;
while (p < region_end)
*p++ = *from++;
}
static inline void __initialize_bss (unsigned int* region_begin, unsigned int* region_end)
{
// Iterate and clear word by word.
// It is assumed that the pointers are word aligned.
unsigned int *p = region_begin;
while (p < region_end)
*p++ = 0;
}
这是怎么回事。
差不多就是这个。
__initialize_data()
并且__initialize_bss()
比您早,即使那会以慢速运行。否则,您必须确保SystemInit()
并且您的Flash_*()
例程完全不使用全局变量。
与全尺寸手臂不同,皮质毫秒使用向量表。它们也没有模式和存储寄存器。对于事件/中断,它们符合ARM编码标准。这意味着您需要的是最低限度的最低要求,但是您选择了最低要求,即地址零的第一个字是堆栈指针的初始值,第二个字是复位时跳转至的地址。使用汇编指令非常容易。
.globl _start
_start:
.word 0x20001000
.word main
但是,只要头两个单词具有正确的值,您就可以做任何您想做的事情。请注意,分支的拇指地址已设置为lsbit。它实际上不是地址的一部分,只是表明我们(停留)在拇指模式下。
您必须消耗一些东西来占用这四个字节,但是如果您使用其他代码来设置堆栈指针,则不必使用向量表,它会加载您放置在其中的内容,那么您可以随时对其进行更改。尽管不像全尺寸/旧式武器,但只有一个堆栈指针。
启动这个词很模糊,所以我可能已经用这些指令覆盖了它,或者根据您的意思,可能需要成千上万的C代码行来完成您的微控制器的启动。
带有STM32的Esp,您必须时钟启用要使用的外围设备,必须针对所需的功能对其进行配置,依此类推。除了每个供应商和产品系列具有不同的逻辑并以不同的方式初始化外,其他任何微控制器都没有什么不同。
来自制造商的启动文件通常被设计为支持C编译器环境。这将包括与设置内存映射,零初始化内存,初始化变量和设置启动(重置向量)有关的大量内容。
一些启动文件还将包括设置中断向量和中断控制器,尽管我所使用的某些环境在单独的汇编语言文件中具有此功能。
有时在启动文件中会看到复杂性,因为基于CPU体系结构支持不同的模型。这些模型可能被命名为“紧凑”和“大”之类的东西。
几乎完全根据您的需求来驱动您所要求的方式。因此,真正要归结为充分了解您的体系结构,所需的环境以及平台的工作方式。然后,您可以修剪供应商提供的文件以满足您的需求,或者从头开始编写自己的文件。
但是,所有这些,如果您打算用C编写代码,最好不要理会启动代码,而只是为编程模型进行设置并将代码集中在main()上。