使用stm32cubemx 创建工程就不说了。安装交叉编译工具链因为之前编译过其他的工程所以我就没重新装过,版本是gcc-arm-none-eabi-4_8-2014q3-20140805-win32
在工程目录下Makefile文件夹的路径里输入cmd回车
结果提示以下错误如下图
arm-none-eabi-gcc build/main.o build/stm32f1xx_it.o build/stm32f1xx_hal_msp.o build/usb_device.o build/usbd_desc.o build/usbd_audio_if.o build/usbd_conf.o build/stm32f1xx_hal_gpio_ex.o build/stm32f1xx_hal_pcd.o build/stm32f1xx_hal_pcd_ex.o build/stm32f1xx_ll_usb.o build/stm32f1xx_hal.o build/stm32f1xx_hal_rcc.o build/stm32f1xx_hal_rcc_ex.o build/stm32f1xx_hal_gpio.o build/stm32f1xx_hal_dma.o build/stm32f1xx_hal_cortex.o build/stm32f1xx_hal_pwr.o build/stm32f1xx_hal_flash.o build/stm32f1xx_hal_flash_ex.o build/stm32f1xx_hal_exti.o build/stm32f1xx_hal_tim.o build/stm32f1xx_hal_tim_ex.o build/stm32f1xx_hal_uart.o build/system_stm32f1xx.o build/usbd_core.o build/usbd_ctlreq.o build/usbd_ioreq.o build/usbd_audio.o build/startup_stm32f103xb.o -mcpu=cortex-m3 -mthumb -specs=nano.specs -TSTM32F103CBTx_FLASH.ld -lc -lm -lnosys -Wl,-Map=build/tx.map,--cref -Wl,--gc-sections -o build/tx.elf
arm-none-eabi-gcc.exe: error: nano.specs: No such file or directory
Makefile:182: recipe for target 'build/tx.elf' failed
make: *** [build/tx.elf] Error 1
arm-none-eabi-gcc.exe: error: nano.specs: No such file or directory这个错误我去网上搜了好久有些解释了这个是干嘛的就是有些简化的c库函数要包含,可是编译结果
提示就是没有这个我找了半天网上都没地方下这个叫newlib_nano的库。
后面再网上看到一篇文章说编译时遇到问题说那个版本的交叉编译工具有bug不能用要换一个版本。
下载后解压我终于看到久违的库文件带nano后缀的库,真是有点喜出望外啊,我特意去看之前的编译工具相对路径里真没这些库文件。晕死,
这个问题我折腾了好几天,网上也找不到解决方法。
于是修改环境变量
重新修改后
输入arm-none-eabi-gcc -v 查看一下路径是否修改成功如下图已改成2019版了
之后重新打开编译窗口先make clean一下再输入make all编译 结果如下 其中一些其他工具需要自行安装像mingw 和cygwin之类的。
在编译成功一个工程后又试了另一个移植了CmBacktrace库,printf使用keil自带的Retarget.c文件重新定向的工程,并且在keil编译通过烧录成功运行。
Retarget.c文件修改部分 因为keil是用 了这个#pragma import(__use_no_semihosting_swi)在用gcc编译时会提示警告 所以我改成下面这样,这样在keil和gcc编译都不会提示警告了
同时 int ferror(FILE *f) 这个在gcc编译也会提示报错所以也添加如下编译选项。
#if defined(__CC_ARM)
#pragma import(__use_no_semihosting_swi)
#elif defined(__GNUC__)
#endif
#if defined(__CC_ARM)
int ferror(FILE *f) {
/* Your implementation of ferror */
return EOF;
}
#elif defined(__GNUC__)
#endif
/******************************************************************************/
/* RETARGET.C: 'Retarget' layer for target-dependent low level functions */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools. */
/* Copyright (c) 2005 Keil Software. All rights reserved. */
/* This software may only be used under the terms of a valid, current, */
/* end user licence from KEIL for a compatible version of KEIL software */
/* development tools. Nothing else gives you the right to use this software. */
/******************************************************************************/
#include <stdio.h>
#include <time.h>
//#include <rt_misc.h>
#include "stm32f1xx_hal.h"
#if defined(__CC_ARM)
#pragma import(__use_no_semihosting_swi)
#elif defined(__GNUC__)
#endif
extern int sendchar(int ch); /* in Serial.c */
extern int getkey(void); /* in Serial.c */
extern long timeval; /* in Time.c */
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
//重定义fputc函数
#if !defined(debug_printf_use)
int fputc(int ch, FILE *f)
{
return (sendchar(ch));
}
#else
#define ITM_PORT8(n) (*(volatile unsigned char *)(0xe0000000 + 4*(n)))
#define ITM_PORT16(n) (*(volatile unsigned short *)(0xe0000000 + 4*(n)))
#define ITM_PORT32(n) (*(volatile unsigned long *)(0xe0000000 + 4*(n)))
#define DEMCR (*(volatile unsigned long *)(0xE000EDFC))
#define TRCENA 0X01000000
int fputc(int ch, FILE *f)
{
if(DEMCR & TRCENA)
{
while(ITM_PORT32(0) == 0);
ITM_PORT8(0) = ch;
}
return ch;
}
#endif
//int fputc(int ch, FILE *f) {
// return (sendchar(ch));
//}
int fgetc(FILE *f) {
return (sendchar(getkey()));
}
#if defined(__CC_ARM)
int ferror(FILE *f) {
/* Your implementation of ferror */
return EOF;
}
#elif defined(__GNUC__)
#endif
void _ttywrch(int ch) {
sendchar (ch);
}
void _sys_exit(int return_code) {
while (1); /* endless loop */
}
/// 重定向c库函数scanf到USART1
int getkey(void)
{
while(!(USART3->SR & UART_FLAG_RXNE));
return ((int)(USART3->DR & 0X1FF));
}
int sendchar(int ch)
{
while(!(USART3->SR & UART_FLAG_TXE)); //循环发送,直到发送完毕
USART3->DR = (uint8_t)ch; //发送数据
// HAL_UART_Transmit(&huart3,(uint8_t *)&ch,1,0xffff); //HAL库用
return ch;
}
改完后编译还是提示错误 提示__sstack 和_estext 没定义
在CmBacktrace库里搜了搜,在cmb_def.h找到了这几行代码
#if defined(__CC_ARM)
/* C stack block name, default is STACK */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME STACK
#endif
/* code section name, default is ER_IROM1 */
#ifndef CMB_CODE_SECTION_NAME
#define CMB_CODE_SECTION_NAME ER_IROM1
#endif
#elif defined(__ICCARM__)
/* C stack block name, default is 'CSTACK' */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME "CSTACK"
#endif
/* code section name, default is '.text' */
#ifndef CMB_CODE_SECTION_NAME
#define CMB_CODE_SECTION_NAME ".text"
#endif
#elif defined(__GNUC__)
/* C stack block start address, defined on linker script file, default is _sstack */
#ifndef CMB_CSTACK_BLOCK_START
#define CMB_CSTACK_BLOCK_START _sstack
#endif
/* C stack block end address, defined on linker script file, default is _estack */
#ifndef CMB_CSTACK_BLOCK_END
#define CMB_CSTACK_BLOCK_END _estack
#endif
/* code section start address, defined on linker script file, default is _stext */
#ifndef CMB_CODE_SECTION_START
#define CMB_CODE_SECTION_START _stext
#endif
/* code section end address, defined on linker script file, default is _etext */
#ifndef CMB_CODE_SECTION_END
#define CMB_CODE_SECTION_END _etext
#endif
#else
#error "not supported compiler"
#endif
在这里可以看到__GNUC__选项了有 4个宏定义只有两个提示没定义,于是
又去网上搜了一圈还是没结果,无奈啊不过也不是没有收获在一篇文章看到说一些参数要在链接器里定义,
这让我想到了之前在创建Makefile工程时stm32cubemx生成的STM32F103C8Tx_FLASH.ld文件。于是打开它瞅瞅,
果然在这个文件开头里我找到了_estack 于是我根据这个文件添加了
_sstack =0x20005000-_Min_Stack_Size; //代码如下
/* Highest address of the user mode stack */
_estack = 0x20005000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x2000; /* required amount of heap */
_Min_Stack_Size = 0x1000; /* required amount of stack */
_sstack =0x20005000-_Min_Stack_Size;
在稍后的位置找到了_etext 于是我添加了
_stext = .; //代码如下
/* The program code and other data goes into FLASH */
.text :
{
_stext = .;
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
完整的ld文件
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : Auto-generated by System Workbench for STM32
**
** Abstract : Linker script for STM32F103C8Tx series
** 64Kbytes FLASH and 20Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed “as is,” without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** <h2><center>© COPYRIGHT(c) 2019 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.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20005000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x2000; /* required amount of heap */
_Min_Stack_Size = 0x1000; /* required amount of stack */
_sstack = 0x20005000-_Min_Stack_Size;
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
_stext = .;
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
修改后保存再次编译 啊哈终于成功了!如下图
不过用gcc编译后空间比用keil编译大的多了 同一个工程keil编译大小如下 才不到20k,gcc编译完都快26k了。哎,先研究到这有空再看看gcc怎么优化大小吧!