« ブログの模様替え | トップページ | GCCでmbedの実行ファイルをコンパイル(2) »

GCCでmbedの実行ファイルをコンパイル

あまりメリットはないのですが、GCC(オフライン環境)でmbedのプログラムをコンパイルして実行することができました。GPIOを直接たたいてオンボードLEDを点滅するだけの単純なプログラムですが一発では動いてくれず苦労しました。以下、GCCを使用したmbedの開発手順です。

開発環境

Windows用のgccやAndroid SDKと同居していますが、ARM関係の開発環境は以下です。

  • Eclipse 3.4.2
  • CDT 5.0.2
  • Zylin Embedded CDT 4.11.1
  • CodeSourcery G++ 4.4.1

LPC 1768用のCMSISライブラリ、その他の入手

このWebページ(Compiling your own CMSIS Code for the mbed)のリンクをたぐってCMSIS Version 1.30をダウンロードし、以下のファイルをプロジェクトディレクトリに展開します。スタートアップコードやリンカースクリプトも入手できます。

  • CMSIS_V1P30/CM3/CoreSupport/core_cm3.c
  • CMSIS_V1P30/CM3/CoreSupport/core_cm3.h
  • CMSIS_V1P30/CM3/DeviceSupport/NXP/LPC17xx/system_LPC17xx.c
  • CMSIS_V1P30/CM3/DeviceSupport/NXP/LPC17xx/system_LPC17xx.h
  • CMSIS_V1P30/CM3/DeviceSupport/NXP/LPC17xx/LPC17xx.h
  • CMSIS_V1P30/CM3/Example/Sourcery G++Lite/LPC17xx/startup_LPC17xx.s
  • CMSIS_V1P30/CM3/Example/Sourcery G++Lite/LPC17xx/LPC17xx.ld
  • CMSIS_V1P30/CM3/Example/Sourcery G++Lite/LPC17xx/main_LPC17xx.c
  • Makefile

リセット時のデフォルト設定でも問題ないと思うのですが、NVICの初期設定も行っています。そのために、Cortex Microcontroller Software Interface Standard(file CMSISとある箇所)から追加のCMSISライブラリをダウンロードして、以下のファイルもプロジェクトディレクトリに展開します。

  • CMSIS\Drivers\include\pc17xx_libcfg_default.h
  • CMSIS\Drivers\source\lpc17xx_libcfg_default.c
  • CMSIS\Drivers\include\lpc17xx_libcfg.h
  • CMSIS\Drivers\include\lpc17xx_nvic.h
  • CMSIS\Drivers\source\lpc17xx_nvic.c

このサイトで手に入るライブラリはSTMicroのPeripheral Libraryと同様の内容でPeripheralをたたくのに便利なライブラリー類です。ソースを見ると作成はNXPのようなことが書いてあるのですが、NXP本家のWebサイトにはPeripheral libraryは見つからず今一素性が不明なのですが、便利なので使っています。
2010/07/27更新: LPC17xx用のCMSISライブラリは、ちゃんとNXP本家でも公開されていました。探し方が悪かった。

Lチカのサンプルコード

system_LPC17xx.cを若干修正しています(PLL0の設定パラメーターをmbedの設定値にあわせるなど)。ソース一式を以下に示します。SystemCoreClock変数初期化のバグを修正しました。
mbed_test_gcc_v2.zip

処理の流れですが、スタートアップコード(startup_LPC17xx.s)から、system_LPC17xx.cのSystemInit()を呼び出しここでPLLの初期設定を行った後で、main_LPC17xx.cのmain()関数を呼び出します。

サンプルプログラムはSysTick割り込みを1ms周期で発生させ、1000msのカウントを行うことによって、mbedオンボードのLED1を1s周期で点滅させます。点滅自体はすぐに動いたのですが、電源On/Offを繰り返すと起動タイミングによって異常に早い周期でLEDが点滅したりし、どうも動作が安定ませんでした。PLLの設定パラメーターを見直したり、NVICの初期化を追加したりしても状況変わらずで挫折しかかっていたのですが、main関数の先頭でSystemCoreClockUpdate()を呼び出すことで問題が解決しました。

原因は、クロック周波数を保持するSystemCoreClock変数が正しく初期化されておらず、誤ったクロック周波数を参照してタイマー周期を計算したためだと思います。具体的には、以下のコードが怪しいです。

/*----------------------------------------------------------------------------
  Define clocks
 *----------------------------------------------------------------------------*/
#define XTAL        (12000000UL)        /* Oscillator frequency               */
#define OSC_CLK     (      XTAL)        /* Main oscillator frequency          */
#define RTC_CLK     (   32000UL)        /* RTC oscillator frequency           */
#define IRC_OSC     ( 4000000UL)        /* Internal RC oscillator frequency   */


/* F_cco0 = (2 * M * F_in) / N  */
#define __M               (((PLL0CFG_Val      ) & 0x7FFF) + 1)
#define __N               (((PLL0CFG_Val >> 16) & 0x00FF) + 1)
#define __FCCO(__F_IN)    ((2 * __M * __F_IN) / __N)
#define __CCLK_DIV        (((CCLKCFG_Val      ) & 0x00FF) + 1)

/* Determine core clock frequency according to settings */
 #if (PLL0_SETUP)
    #if   ((CLKSRCSEL_Val & 0x03) == 1)
        #define __CORE_CLK (__FCCO(OSC_CLK) / __CCLK_DIV)
    #elif ((CLKSRCSEL_Val & 0x03) == 2)
        #define __CORE_CLK (__FCCO(RTC_CLK) / __CCLK_DIV)
    #else
        #define __CORE_CLK (__FCCO(IRC_OSC) / __CCLK_DIV)
    #endif
 #else
    #if   ((CLKSRCSEL_Val & 0x03) == 1)
        #define __CORE_CLK (OSC_CLK         / __CCLK_DIV)
    #elif ((CLKSRCSEL_Val & 0x03) == 2)
        #define __CORE_CLK (RTC_CLK         / __CCLK_DIV)
    #else
        #define __CORE_CLK (IRC_OSC         / __CCLK_DIV)
    #endif
 #endif


/*----------------------------------------------------------------------------
  Clock Variable definitions
 *----------------------------------------------------------------------------*/
uint32_t SystemCoreClock = __CORE_CLK;/*!< System Clock Frequency (Core Clock)*/

上記のコードで、19行目の__CORE_CLK、39行目のSystemCoreClockが正しく設定されないのではと思います。Cのマクロはどうも苦手です・・

2010/5/22追記:SystemCoreClockが初期化されない理由が判明。その2に原因を記載しました。

今後の予定

UARTを使ってコンソール出力ができるようにしたいと思っています。Printf関数をリンクできるようにするのが目標です。なぜこんなことをやっているかというと、mbedのオンラインIDEで動いているARM純正コンパイラとGCCで、最適化レベルやコードサイズを比較してみたいためです。

ちなみに、今回gccでコンパイルしたLチカコードはbinファイルで2,992バイトに対して、mbedオンラインIDEで作成した同等のコードサイズは9,876バイトになりました。ただ、gcc版はスタートアップコードや初期化コードで必要最小限の処理しか行っていないため、今回の条件ではコードサイズの比較はできないと思います。

« ブログの模様替え | トップページ | GCCでmbedの実行ファイルをコンパイル(2) »

mbed」カテゴリの記事

コメント

この記事へのコメントは終了しました。

2018年10月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
無料ブログはココログ