2016年5月24日 星期二

[STM32] 解決 sprintf...etc 或 maco函數無法編譯的問題

接上一篇,
如果遭遇到, 當使用了一些 standard C 函式庫之後, 且 compile 無法正常編譯過,

Error Message:
c:/program files (x86)/gnu tools arm embedded/5.2 2015q4/bin/../lib/gcc/arm-none-eabi/5.2.1/../../../../arm-none-eabi/lib/armv7-m\libg.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'
collect2.exe: error: ld returned 1 exit status
make: *** [USART_String.elf] Error 1


請試著使用以下方法,

1, 在 stm32_flash.ld 檔案找到如下這段, 然後在最後面加上 PROVIDE (__HEAP_START = _end);  

  /* 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

  PROVIDE ( end = _ebss );
  PROVIDE ( _end = _ebss );
  PROVIDE (__HEAP_START = _end);

2, 在 USER 資料夾內, 創建一個新的檔案 syscalls.c , 並在裡面添加下面這些 code.

#include <sys/types.h>
// for use malloc sprintf function
extern int  __HEAP_START;

caddr_t _sbrk ( int incr ){
  static unsigned char *heap = NULL;
  unsigned char *prev_heap;

  if (heap == NULL) {
    heap = (unsigned char *)&__HEAP_START;
  }
  prev_heap = heap;


  heap += incr;

  return (caddr_t) prev_heap;
}


儲存, 應該就可以正常編譯了.

2016年5月5日 星期四

[STM32] 使用 Eclipse + GCC ARM 在 WIN7 建立 STM32 開發環境

仿間的教學書籍都是建議使用 MDK 來進行 STM32 的開發, 但是它畢竟是商業軟件, 在未授權下使用, 畢竟比較麻煩.

在此提供 Eclipse + GCC ARM tool 的方式, 兩個軟體都是 opensource, 可以放心使用, 不會一直收到公司郵件通知............>_<

事前準備:
    1, 編譯工具 GCC ARM Embedded Tool-chain
        下載連結: Download Link
        這是由 ARM 維護的 GCC 編譯器, 下載 win32 版本的 zip 檔, 解壓縮後放到你要放的目錄下, 也可下載 exe 檔, 安裝完後應該會在 C:\program file\ 資料夾下面.

    2, Eclipse IDE for C/C++ Developers Tool
        下載連結: Download Link
        請至上方連結下載 Eclipse Tool, 則依您 PC 的屬性選擇 32bit 或 64bit , 而 Eclipse 是跑在 Java runtime environment(JRE) 下,
        所以您必須至 Java 網站下載 JRE 並安裝, 當然如果你安裝過了, 就不需要了.
        JRE 下載連結: Download Link
 
    3, The ARM-based 32-bit MCU STM32F10x Standard Peripheral Library
        下載連結: Download Link
        我是使用 V3.5.

    4, STM32 開發版
        我的開發版是 STM32F103ZET6 Evaluation Board

安裝 Eclipse:
        安裝完 GCC ARM 與 Eclipse 後, 開啟 Eclipse.
        Eclipse 會跳出一視窗確認您的 workspace 路徑, 請選擇您要放置專案的路徑, 並按下 OK .


        進入開發介面後, 點選 Help -> Install New Software... 安裝 CDT.
        在 Work with 輸入 cdt, 即會自動跑出 CDT 連結, 在連結上 double click. 下方會跑出三個選單, 請選擇第二個 CDT Optional Features.

        請選擇 C/C++ GCC Cross Compiler Support, 並按 Next...........依照步驟完成安裝.

        安裝完 CDT 後, 請重新啟動 Eclipse.


建立一個簡單的 LED 專案:
        在此建立一個簡單的 LED 閃爍專案.
     
        請在 Eclipse 介面中點選 File -> New -> C Project
        如下範例: 輸入 Project name "LED_Test", Toolchains 選擇 Cross ARM GCC -> Next.

        Next -> 確認 Toolchains name 是否為一開始所安裝的 GCC ARM tool, 確定即可按 Finish.

        完成後, 會在 Project Explorer 看到新增一個 LED_Test 專案, 並且會跑出三個 Includes 路徑,
        如果這三個路徑沒跑出來, 請重新檢察 Toolchains 的路徑, 否則之後會無法編譯.


        打開一開始所設定的 workspace 資料匣, 會發現已經多了一個 LED_Test 資料夾, 請在這資料夾內再多創建三個資料夾如下,
        CMSIS 資料夾
                將 core_cm3.c, core_cm3.h, stm32f10x.h, system_stm32f10x.c, system_stm32f10x.h 這五個檔案複製進來,
                這五個檔案可以在 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3 的 CoreSupport 與 DeviceSupport 資料夾內找到;
                緊接著再創建一個資料夾 "startup", 然後將 startup_stm32f10x_hd.S 與 stm32_flash.ld 複製進去,
                "startup_stm32f10x_hd.S" 可以在 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO 資料夾內找到,
                依CPU的晶片類型選擇所需要的檔案, 要注意的是原始檔案的 *.s 是小寫, 請改成大寫, 否則 Eclipse 看不懂.
                stm32_flash.ld 連結檔可以在 STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template\TrueSTUDIO 資料夾內找到,
                依CPU的晶片類型選擇所需要的檔案, 可將 stm32_flash.ld 打開來看看是不是你的CPU所適用的.
        FWlib 資料夾
                至 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver 資料夾內, 將 inc 與 src 資料夾複製近來.
        USER 資料夾
                所寫的 code, 如 main.c 都放在這個資料夾中, 並將 stm32f10x_conf.h, stm32f10x_it.c, stm32f10x_it.h 也複製進來,
                可在 STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template 資料夾內找到這幾個檔案.

                 創建完後, 如下圖即可,

                接著再做一些 Compiler 與 Linker 的相關設定, 在 LED_Test 這個 Project Name 上按右鍵, 並選擇 properties,
                選擇 C/C++ Build -> Setting -> Preprocessor -> Defined symbols 選 Add,
                加入 USE_STDPERIPH_DRIVER 與 STM32F10X_HD 這兩個 Symbol,
                -> 然後 Scroll bar 往下拉 -> Apply

                點選 Includes, 在 Includes paths 選 Add, 將 CMSIS, FWlib/inc, FWlib/src, USER 這幾個資料夾都加進來.
                -> 然後 Scroll bar 往下拉 -> Apply

                點選 Cross ARM C Linker -> General , 在 Script files 選 Add, 將一開始存放的 stm32_flash.ld 加進來,
                -> 然後 Scroll bar 往下拉 -> Apply

                在同一個頁面上方點選 Build Steps,
                然後在 Post-build steps 的 Command 加上 arm-none-eabi-objcopy -S -O binary "${ProjName}.elf" "${ProjName}.bin"
                在 Description 內加上 Create Binary.
                -> 然後 Scroll bar 往下拉 -> Apply -> OK 完成設定.

                修改 main.c 檔如下, 我所使用的是 STM32F103ZET6 Evaluation Board,
                以下的 sample code 可以使板上的 3 個 LED 輪流閃爍.
========================================================================
  1. #include "stm32f10x.h"

  2. void LED_GPIO_Config(void);
  3. void Delay(__IO u32 nCount);

  4. int main(void)
  5. {
  6. LED_GPIO_Config();

  7.   /* Infinite loop */
  8. while (1)
  9. {
  10. GPIO_SetBits(GPIOF, GPIO_Pin_6);
  11. Delay(0x0FFFEF);
  12. GPIO_ResetBits(GPIOF, GPIO_Pin_6);
  13. GPIO_SetBits(GPIOF, GPIO_Pin_7);
  14. Delay(0x0FFFEF);
  15. GPIO_ResetBits(GPIOF, GPIO_Pin_7);
  16. GPIO_SetBits(GPIOF, GPIO_Pin_8);
  17. Delay(0x0FFFEF);
  18. GPIO_ResetBits(GPIOF, GPIO_Pin_8);
  19. Delay(0x0FFFEF);
  20. }
  21. }

  22. void LED_GPIO_Config(void)
  23. {
  24. GPIO_InitTypeDef GPIO_InitStructure;

  25. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);

  26. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;

  27. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  28. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  29. GPIO_Init(GPIOF, &GPIO_InitStructure);

  30. GPIO_SetBits(GPIOF, GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8);
  31. }

  32. void Delay(__IO u32 nCount)
  33. {
  34. for(; nCount != 0; nCount--);
  35. }


========================================================================

                儲存 main.c 後, 在 LED_Test project name 上按右鍵, 點選 Build Project, 即開始 Compiler.
                Compiler 完成後, 會顯示下面訊息,
             
                .....
                .....
                .....
                Finished building target: LED_Test.elf

                make --no-print-directory post-build
                Create Binary
                arm-none-eabi-objcopy -S -O binary "LED_Test.elf" "LED_Test.bin"

                Invoking: Cross ARM GNU Create Flash Image
                arm-none-eabi-objcopy -O ihex "LED_Test.elf"  "LED_Test.hex"
                Finished building: LED_Test.hex

                Invoking: Cross ARM GNU Print Size
                arm-none-eabi-size --format=berkeley "LED_Test.elf"
                text   data    bss    dec    hex filename
                2216   1076    540   3832    ef8 LED_Test.elf
                Finished building: LED_Test.siz



                在 Debug 資料夾內會產生出 hex file 與 bin file,
                我是使用 FlyMcu.exe 這個軟體, 使用 com port 即可下載 hex file, 網路上都 download 的到FlyMcu,
                 ST-Link 或 J-Link 燒錄與 Debug 方式之後有空再說吧.


                 需要注意的事是, 在編譯的過程中, core_cm3.c 有可能會編譯不過, 請打開這個檔案, 將 uint32_t __STREXB(uint8_t value, uint8_t *addr)函數和uint32_t __STREXH(uint16_t value, uint16_t *addr)函數裡面的 "=r" 改為 "=&r", 應該就可以編譯成功了.