之前从网上下载了一份用GCC开发stm32的程序,也是用的stm32的库函数编程,启动文件是startup_stm32f10x_hd.s,链接脚本文件是从gcc_ride7中拷贝出的stm32f10x_flash_extsram.ld,做了些简单修改。但是编译了一下,出现了一大堆的错误。于是干脆不用这些文件,从网上查资料,自己写启动文件和链接脚本。仔细看了下startup_stm32f10x_hd.s,这个文件,发现也很简单,无非是定义了一些中断向量表和完成数据段的搬移和.bss段的清零等工作,并把程序跳转到main()函数。然后链接脚本文件告知链接器,把所有目标文件相应的段连接到一起,并把目标文件中的“变量地址”“函数地址”重定位至正确的地址空间; 编写前需要知道C程序编译后的典型内存布局 ,单片机的启动流程以及链接脚本文件的作用和编写等知识。部分知识,摘自网络。
《Cortex-M3权威指南》一书中有如下开发流程图:
一、下载GNU工具链,搭建环境
二、熟悉整体的开发流程
三、编写一个最精简的代码for(pulDest = &_data; pulDest < &_edata; )
{
*pulDest++ = *pulSrc++;step4: 使用官方的flash下载demo程序将得到的gpio_test.bin通过usart1烧录至芯片。
五、下载程序和仿真调试
如果只是下载程序,可以通过串口,用官方提供的下载工具下载。
如果有jlink仿真器,可以用jiinkARM工具下载,这个工具在安装jlink驱动的时候已经安装了。
调试和仿真,linux下可以用openocd和openjtag,或者用GDB加jlink的GDBserver,windows下可以用GDBserver和可视化的GDB调试器insight。
以下是一个简单的流水灯示例和makefile,库使用的是3.5的官方库
/*************************************************/
/* filename: stm32f103VET6.ld */
/* linkscript for STM32F103VET6 microcontroller */
/* */
/*************************************************/
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x80000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
}
/* Section Definitions */
SECTIONS
{
.isr_vector :
{
KEEP(*(.isr_vector))
isr.o(.text)
. = ALIGN(4);
_eisr_vector = .;
}
.text : AT (_eisr_vector)
{
_text = .;
*(EXCLUDE_FILE(isr.o) .text)
*(.rodata)
. = ALIGN(4);
_etext = .;
} > SRAM
.data :
{
_data = .;
*(.data)
. = ALIGN(4);
_edata = . ;
} > SRAM
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
_bss = . ;
*(.bss)
. = ALIGN(4);
_ebss = . ;
} > SRAM
_end = . ;
}
//isr.c文件,省略号代表没写全,可以找.s启动文件中把它补全
extern int main(void);
void ResetISR(void);
void NMIException(void);
void HardFaultException(void);
...
typedef void (*pfnISR)(void); // Pointer to exception handle function
__attribute__ ((section(".isr_vector")))
pfnISR VectorTable[] =
{
(pfnISR)(0x20010000), // The initial stack pointer is the top of SRAM
ResetISR, // The reset handler
NMIException,
HardFaultException,
...
};
//*****************************************************************************
//
// The following are constructs created by the linker, indicating where the
// the "data" and "bss" segments reside in memory. The initializers for the
// for the "data" segment resides immediately following the "text" segment.
//
//*****************************************************************************
extern unsigned long _eisr_vector;
extern unsigned long _text;
extern unsigned long _etext;
extern unsigned long _data;
extern unsigned long _edata;
extern unsigned long _bss;
extern unsigned long _ebss;
void ResetISR(void)
{
unsigned long *src, *dst;
// copy the text segment from flash to SRAM
src = &_eisr_vector;
dst = &_text;
while (dst < &_etext) {
*dst++ = *src++;
}
// Copy the data segment initializers from flash to SRAM.
dst = &_data;
while (dst < &_edata) {
*dst++ = *src++;
}
// Zero fill the bss segment.
for(dst = &_bss; dst < &_ebss; dst++) {
*dst = 0;
}
// Call the application's entry point.
main();
}
//main.c文件
#include "stm32f10x.h"
GPIO_InitTypeDef GPIO_InitStructure;
void RCC_Configuration(void);
void Delay(__IO uint32_t nCount);
int main(void)
{
//uint16_t a;
/* System Clocks Configuration **********************************************/
RCC_Configuration();
//
/* Configure all unused GPIO port pins in Analog Input mode (floating input
trigger OFF), this will reduce the power consumption and increase the device
immunity against EMI/EMC *************************************************/
RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 |RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //D1 D2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_13;//D3, D4
GPIO_Init(GPIOD, &GPIO_InitStructure);
while (1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_6);// D1亮
Delay(0xAFFFF);
GPIO_SetBits(GPIOC, GPIO_Pin_7 ); //D2亮
GPIO_ResetBits(GPIOC, GPIO_Pin_6); //D1灭
Delay(0xAFFFF);
GPIO_SetBits(GPIOD, GPIO_Pin_13 ); //D3亮
GPIO_ResetBits(GPIOC, GPIO_Pin_7); //D2灭
Delay(0xAFFFF);
GPIO_SetBits(GPIOD, GPIO_Pin_6 ); //D4亮
GPIO_ResetBits(GPIOD, GPIO_Pin_13); //D3灭
Delay(0xAFFFF);
GPIO_ResetBits(GPIOD, GPIO_Pin_6); //D4灭
}
}
void RCC_Configuration(void)
{
/* Setup the microcontroller system. Initialize the Embedded Flash Interface,
initialize the PLL and update the SystemFrequency variable. */
SystemInit();
}
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
//编译本工程的makefile文件
BINARY = main
rm -f *.list
完
本工程的示例代码放在了CSDN上,可以免费下载。搭建好环境后只需要make一下,就能生成.hex和.bin文件。注意开启-O2优化,生成的代码和keilMDK比了比,差不多大。但不开启-O2优化,生成代码量是keil for arm的两倍多。