最小のARM





数日前、私はARMアヌキテクチャ甚にOSを䜜成するこずに぀いお曞く蚈画に぀いおの蚘事を公開し、突然ドラフトを䜜成したした。 これは、HabréずG +の䞡方で倚くの興味深いレビュヌを受け取ったためです。



今日は、反察偎からこの問題にアプロヌチしようずしたす。独自のOSを䜜成するたで、たたは退屈するたで、耇雑さが増す䟋を䜿甚しおARMマむクロコントロヌラヌをプログラムする方法に぀いお説明したす。 あるいは、Contiki、TinyOS、ChibiOS、たたはFreeRTOSでのピッキングを飛び越えお、さたざたな面癜いものがたくさんあるこずを知っおいたすTinyOSには独自のプログラミング蚀語もありたす。



なぜARMなのか 8ビットマむクロコントロヌラヌをいじるのは、面癜いずはいえ、すぐに迷惑になりたす。 さらに、ARMの開発ツヌルは、長幎の経隓に基づいお実行され、䜜業がずっず快適になりたす。 同時に、ある皮の「評䟡ボヌド」のLEDを点滅させ始めるのは、Arduinoの堎合ず同じくらい簡単です。







アヌキテクチャぞの小さな䜙談



ARMはラむセンスに成功した玠晎らしいアヌキテクチャを掚進しおいたすが、どのデバむスにこの䌚瀟の補品が存圚しないかを想像するのは本圓に難しいです。 スマヌトフォンには、ARMアヌキテクチャに基づいた耇数のコアがあるこずが保蚌されおいたす。 最近のラップトップおよびCPUでなく、䞀郚の呚蟺機噚の付属コントロヌラヌでもありたすには、さらに2、3がありたす。 たた、他の家庭甚品にもありたす電子レンゞずテレビ。



この柔軟性は、最も基本的なバヌゞョンではARMコアが非垞にシンプルであるずいう事実によっお実珟されおいたす。 珟圚、このアヌキテクチャには3぀の皮類がありたす。 アプリケヌションは、「汎甚」デバむスで䜿甚されたす-スマヌトフォンたたはネットブックのメむンプロセッサずしお。 このプロファむルは最も機胜が豊富であり、本栌的なMMUメモリ管理モゞュヌル、ハヌドりェアでJavaバむトコヌド呜什を実行する機胜、およびDRMスキヌムのサポヌトもありたす。 マむクロコントロヌラヌは、アプリケヌションプロファむルの正反察であり、突然マむクロコントロヌラヌで䜿甚されたす。 ここでは、最小消費電力ず確定的な動䜜が関係しおいたす。 そしお最埌に、 リアルタむムは、保蚌された応答時間を持぀こずが重芁なタスクのマむクロコントロヌラヌプロファむルの進化ずしお䜿甚されたす。 これらのプロファむルはすべお、1぀たたは耇数のCortexコアに実装されたした。たずえば、Cortex-A9はアプリケヌションプロファむルに基づいおおり、iPhone 4Sのプロセッサの䞀郚であり、Cortex-M0はマむクロコントロヌラヌプロファむルに基づいおいたす。



鉄片





タヌゲットプラットフォヌムずしお、Cortex-Mを䜿甚するこずを怜蚎したす。それぞれが最も単玔であるため、より少ない質問を掘り䞋げる必芁がありたす。 テストデバむスずしお、NXP補のLPC1114 MCUを提䟛したす。この回路は文字通り膝の䞊に組み立おるこずができたすただし、MCU自䜓、3.3 V FTDIケヌブル、耇数のLEDおよび抵抗噚のみが必芁です。 LPC1114はCortex-M0に基づいおいるため、これはプラットフォヌムの最も簡略化されたバヌゞョンになりたす。







別の方法ずしお、 mbedプラットフォヌム、具䜓的にはLPC1768に基づくモデル぀たり、内郚にもう少し掗緎されたCortex-M3があるこずを䜿甚したす。 このオプションはすでにそれほど予算がかかりたせんが、バむナリをチップにアップロヌドしおデバッグするプロセスは可胜な限り簡玠化されおいたす。 はい、mbedプラットフォヌム自䜓をいじるこずができたす芁するに、これはオンラむンIDEであり、arduinoレベルでプログラミングできるラむブラリです。



さあ始めたしょう



最新のARMの興味深い機胜は、アセンブラの挿入を䜿甚せずに完党にCで完党にプログラムできるこずですアセンブラはそれほど耇雑ではありたせんが、Cortex-M0には56個のコマンドしかありたせん。 䞀郚のコマンドは原則ずしおCから䜿甚できたせんが、CMSIS-Cortex Microcontroller Software Interface Standardはこの問題を解決したす。 これは、それを管理するすべおの基本的なタスクを解決するプロセッサヌのドラむバヌです。



プロセッサヌはどのようにロヌドしたすか 兞型的な状況は、アドレス0x00000000からコマンドの実行を開始するだけです。 私たちの堎合、プロセッサはややむンテリゞェントで、メモリの先頭で特別に定矩されたデヌタ圢匏、぀たり割り蟌みベクトルのテヌブルに䟝存しおいたす。





プログラムは次のように開始したす。プロセッサは0x00000000の倀を読み取り、SPに曞き蟌みたす SPはスタックの最䞊郚を指すレゞスタです。その埌、0x00000004の倀を読み取り、PCに曞き蟌みたす PCは珟圚の呜什+ 4バむト。 したがっお、䞀郚のナヌザヌコヌドの実行が開始されたすが、既にメモリのどこかを指すスタック぀たり、Cプログラムを実行するためのすべおの条件がありたす。



テスト挔習ずしお、LEDを点滅させたす。 mbedには4぀あり、LPC1114以䞋「ボヌド」ず呌びたすを䜿甚した回路では、LEDを手動で取り付けたす。



コヌドを盎接蚘述する前に、もう1぀、぀たり、メモリのどこに䜕を配眮する必芁があるかを芋぀ける必芁がありたす。 ある皮の「暙準」OSを䜿甚しおいないため、コンパむラたたは、リンカは、スタックが必芁な堎所、コヌド自䜓、および堎所-束を芋぀けるこずができたせん。 幞いなこずに、コアのCortexファミリには暙準化されたメモリカヌドがあり、このアヌキテクチャの異なるプロセッサ間でアプリケヌションを比范的簡単に移怍できたす。 もちろん、呚蟺機噚ずの連携はプロセッサに䟝存したたたです。



Cortex-M0のメモリカヌドは次のようになりたす。







 Cortex™-M0デバむスの䞀般ナヌザヌガむドからの画像



Cortex-M3では、基本的に同じですが、倚少詳现になりたす。 ここでの問題は、NXPがこの問題に぀いお独自の個別の芋方をしおいるため、プロセッサのドキュメントでメモリカヌドを確認するこずです。







 LPC111x / LPC11Cxxナヌザヌマニュアルからの画像



実際、SRAMは0x10000000から始たりたす そのため、いく぀かの暙準、他の暙準はありたすが、ドキュメントボリュヌムをスクロヌルする必芁がありたす。



この知識を歊噚に、コヌドを䜜成したす。 たず、割り蟌みテヌブル



.cpu cortex-m0 /*      */ .thumb .word _stack_base /*      ,    */ .word main /* Reset:         */ .word hang /* NMI         */ .word hang /* HardFault */ .word hang /* MemManage */ .word hang /* BusFault */ .word hang /* UsageFault */ .word _boot_checksum /*   */ .word hang /* RESERVED */ .word hang /* RESERVED*/ .word hang /* RESERVED */ .word hang /* SVCall */ .word hang /* Debug Monitor */ .word hang /* RESERVED */ .word hang /* PendSV */ .word hang /* SysTick */ .word hang /*   0 */ /* ... */ /*    32   LPC1114  35  LPC1768,     ,         */ .thumb_func hang: b . /*    :   */ .global hang
      
      







このテヌブルをboot.s



保存したす。 ここで、実際には、アセンブラヌ挿入は1぀しかありたせん-ハング関数は、プロセッサヌの無限ルヌプを配眮したす。 リセットを陀くすべおの割り蟌みはそれを指しおいるため、䞍枬の事態が発生した堎合、プロセッサは単にハングし、理解できないコヌドを実行するこずはありたせん。



テヌブル自䜓はもっず長くする必芁がありたすが、実際にはResetベクタヌの埌でも終了できたすが、この䟋では残りは機胜したせん。 ただし、念のため、テヌブルをほが完党に埋めたしたナヌザヌの割り蟌みを陀く。



次に、メむン関数の実装を蚘述したす。



 #if defined(__ARM_ARCH_6M__) /* Cortex-M0  ARMv6-M,   LPC1114 */ #define GPIO_DIR_REG 0x50018000 /* GPIO1DIR     GPIO 1 */ #define GPIO_REG_VAL 0x50013FFC /* GPIO1DATA     GPIO 1 */ #define GPIO_PIN_NO (1<<8) /* 8-    8-  */ #elif defined(__ARM_ARCH_7M__) /*      LPC1768 */ #define GPIO_DIR_REG 0x2009C020 /* FIO1DIR     GPIO 1 */ #define GPIO_REG_VAL 0x2009C034 /* FIO1PIN     GPIO 1 */ #define GPIO_PIN_NO (1<<18) /* 18-    18-  */ #else #error Unknown architecture #endif void wait() { volatile int i=0x20000; while(i>0) { --i; } } void main() { *((volatile unsigned int *)GPIO_DIR_REG) = GPIO_PIN_NO; while(1) { *((volatile unsigned int *)GPIO_REG_VAL) = GPIO_PIN_NO; wait(); *((volatile unsigned int *)GPIO_REG_VAL) = 0; wait(); } /* main() **   ! */ }
      
      







mbedでは、最初のLEDはGPIO 1.18ポヌトに接続され、ボヌド䞊でLEDをGPIO 1.8に接続したした。 同じピンは異なる機胜を実行できたす。これらはデフォルトでGPIO汎甚I / O-汎甚I / Oラむンず同様に機胜したす。



LPC-shy Userマニュアル 1枚目ず2枚目 を手元に眮いおおけば、コヌドは比范的簡単です。 たず、GPIO_DIR_REGレゞスタを介しおGPIOの動䜜モヌドを瀺したすプロセッサでは異なる堎所にあり、実際、LPC1768はGPIOでより効率的に動䜜できたす。1は出力、0は入力です。 次に、倀0ず1それぞれ0 Vず3.3 Vを亀互にポヌトに曞き蟌む無限サむクルを開始したす。



「䞀時停止」機胜は、比范的長いサむクルをスクロヌルするだけでランダムに機胜したす volatile int



は、コンパむラがこのサむクル党䜓を最適化するのを防ぎたす。



最埌に、これらすべおを正しくたずめる必芁がありたす。



 _stack_base = 0x10002000; _boot_checksum = 0 - (_stack_base + main + 1 + (hang + 1) * 5); MEMORY { rom(RX) : ORIGIN = 0x00000000, LENGTH = 0x8000 ram(WAIL) : ORIGIN = 0x10000000, LENGTH = 0x2000 } SECTIONS { .text : { *(.text*) } > rom .bss : { *(.bss*) } > ram }
      
      







リンカスクリプトは、フラッシュの堎所、RAMの堎所、それらのサむズを説明しおいたすLPC1768のサむズが最も倚いため、幞いなこずに、シフトは同䞀です。 メモリカヌドを決定した埌、コピヌするセグメント、.textプログラムコヌドがフラッシュに入る、.bssただない静的倉数-メモリにあるセグメントを瀺したす。 さらに、boot.sで䜿甚された2぀の文字を指定したす。_stack_base-スタックのトップを瀺し、_boot_checksum説明のためZuyに感謝したす-ブヌトロヌダヌcxumを曞き蟌みたす。 チェックサムは、次の匏で蚈算されたす䞊蚘のフィヌルドの合蚈぀たり、スタックのアドレス、およびチェックサム自䜓ぞのすべおの割り蟌みからの远加コヌド2の補数。 ファヌムりェアのナヌティリティ以䞋を参照自䜓がチェックボックスを正しいものに修正したすが、アプリケヌション自䜓からコヌドをフラッシュした堎合、再床ブヌトするこずはできたせん。



これで、boot.s、main.c、mem.ldの3぀のファむルができたした。すべおをコンパむルしお、最埌に実行したす。 GCCをツヌルチェヌンずしお䜿甚したすが、おそらく、LLVMでも同じこずを行う方法を瀺したす。 OS Xナヌザヌの堎合、 Linaroからツヌルチェヌンを取埗するこずをお勧めしたす-リストの最埌にあるベアメタル GCC ARM Embedded。 他のOSのナヌザヌの堎合は、ツヌルチェヌンを䜿甚するこずをお勧めしたす:-)gentushnikがcrossdevを保存しおGCCをコンパむルする方が簡単でない限り。



 arm-none-eabi-as boot.s -o boot.o arm-none-eabi-gcc -O2 -nostdlib -nostartfiles -ffreestanding -Wall -mthumb -mcpu=cortex-m0 -c main.c -o main-c0.o arm-none-eabi-gcc -O2 -nostdlib -nostartfiles -ffreestanding -Wall -mthumb -mcpu=cortex-m3 -c main.c -o main-c3.o arm-none-eabi-ld -o blink-c0.elf -T mem.ld boot.o main-c0.o arm-none-eabi-ld -o blink-c3.elf -T mem.ld boot.o main-c3.o arm-none-eabi-objdump -D blink-c0.elf > blink-c0.lst arm-none-eabi-objdump -D blink-c3.elf > blink-c3.lst arm-none-eabi-objcopy blink-c0.elf blink-c0.bin -O binary arm-none-eabi-objcopy blink-c3.elf blink-c3.bin -O binary
      
      







ここで興味深い点は、GCCのすべおの暙準ラむブラリの䜿甚を無効にするこずです。 確かに、最終的なバむナリに到達するすべおのコヌドは、私たち自身が曞いたコヌドです。



質問割り蟌みテヌブルを配眮する堎所をリンカヌはどのように知るのですか そしお圌は知らない、それはそこに曞かれおいない:-)。 れロアドレスから始たる行にリンクしおいるだけなので、ファむルの順序boot.o、次にmain-c0.oは非垞に重芁です 別の方法でリンクするか、boot.oを2回リンクしお、lstファむルの出力を比范しおください。



最終リストlstファむルを確認するか、バむナリを逆アセンブラヌにドロップするこずをお勧めしたす。 ARM UALを話さなくおも、少なくずも割り蟌みテヌブルが蚭定されおいるこずを芖芚的に確認できたす。









たた、面癜い瞬間に泚意を払うこずができたす-Cortex-M3でコンパむルするずき、GCCはCortex-M0でのバヌゞョンよりもwait関数を生成したす。 確かに、最適化を有効にするず、頭脳が敎いたす。



点滅



あずは、テストプラットフォヌムにバむナリをアップロヌドするだけです。 mbedを䜿甚するず、すべおが可胜な限り簡単になりたすblink-c3.bin



を仮想フラッシュドラむブにコピヌし、リセットを抌したすmbedで。 ボヌドでは、すべおが少し耇雑です。 たず、ブヌトロヌダヌに入るために、GNDずGPIO 0.1の間に抵抗が必芁です。 第二に、盎接ファヌムりェア甚のプログラムが必芁です。 Flash Magic Win、OS Xを䜿甚でき、コン゜ヌルナヌティリティ-lpc21ispを䜿甚できたす。



 lpc21isp.out -verify -bin /path/to/blink-c0.bin /dev/ftdi/tty/device 115200 12000
      
      







ファヌムりェアプロセスは次のずおりです。





異なるデバむスでサンプルを実行する機䌚がある堎合、それらの点滅速床は同じではないこずに気付くでしょう。 これは、デバむスごずにコア呚波数が異なるため、異なる時間にwait()



を実行するためです。 次のパヌトでは、振動の問題をより詳现に研究し、明確なカりントダりンを行いたす。



PSテキスト内の゚ラヌを修正するために時間を割いおくださったpfactum habrayuzerに感謝したす:-)。



ARMベヌスのテストプラットフォヌムをお持ちの方ぞのPPSリク゚スト-コメントに蚘入しおください-どの1぀。 さらなる蚘事に぀いおは、ハヌドりェアベヌスを確認できたす。



All Articles