使用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不能用要換一個版本。於是我就抱着試一試的心態去下了一個最新版本鏈接如下
https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-win32.zip
下載后解壓我終於看到久違的庫文件帶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怎么優化大小吧!