Cortex-Mコア全般プログラミングガイド

EWARMで開発するCortex-M
プログラミングガイド
April 2015
IAR Systems K.K.
FAE Team
本ドキュメントについて
目的
 Cortex-Mプロセッサファミリの特徴を理解し、ソフトウェア開発をする上
での注意事項を学ぶ。ARM用統合開発環境、ARM用IAR Embedded
Workbench(EWARM)を用いて、実際の開発を理解する。
内容
 ARM Cortex-Mの概要
 Cortex-Mの命令セット
 Cortex-Mのレジスタ
 Cortex-Mの割込みハンドリング
 スタートアップ処理
 リンカ設定でメモリ配置コントロール
 Cortex-Mへの移行時の注意点
 解析ツールを使用して、品質向上
※本ドキュメントは、2015年4月現在のIARシステムズWebサイト、ST社Webサイト、
およびEWARMバージョン7.40.2を元に作成しています。
2
IAR SYSTEMS— A LEADING GLOBAL VENDOR
168 Employees with HQ in Uppsala, Sweden
Listed in Stockholm/Nasdaq
R&D investment 32% of revenue
32 years in the industry
24 hour technical support in
13 languages
Uppsala
Munich
Sao Paulo
Tokyo
Seoul
Shanghai
London
Paris
San Francisco
Dallas
Boston
Los Angeles
+Distributor representation in
43 countries
Stability and growth
Licenses
# (000’s)
2010 - 2013
Operating
Margin %
20
20
15
15
10
10
5
5
0
0
2010
2011
License #
2012
2013
Operating Margin
ARM Cortex-Mの概要
Cortex-Mベースのマイコンとは
英ARM Limitedの設計・開発するARM プロセッサを採用したマイコン
ARMはCPUコア(など)のIP(設計図)を販売
ARM
チップベンダが周辺機能(ペリフェラル)や
メモリを追加実装
周辺機能
周辺機能
周辺機能
周辺機能
メモリ
メモリ
メモリ
メモリ
ARM コア
ARM コア
ARM コア
ARM コア
A社
B社
C社
D社
5
クラシックARMとARM Cortexプロセッサファミリ
ARMマイコンの進化の過程
ARM11
Cortex-Ax
Application
Processors
Cortex-Rx
Real Time
Processors
ARM9
ARM7
CortexM0
V4
Microcontrollers
Cortex-Mx
V5
クラシックARM
V6
V7
“基本的に” xが
大きいほど処理能力大
ARM Cortex
6
クラシックARMとARM Cortex-M
ARM7(v4)とCortex-M3/4(v7-M)の主要な違い
ARM7
Cortex-M3/M4
アーキテクチャ
ARM v4
ARM v7-M
命令セット
ARM / Thumb
Thumb2
DMIPS / MHz
0.93
1.25
割込みコントローラ
外部
ネスト型ベクタ割込みコントローラ(NVIC)
ベクタテーブル方式
命令方式
アドレス方式
アセンブラ要不要
要
不要
タイマー
外付け
Systickタイマー内蔵
モード
User
FIQ
IRQ
SuperViser
Monitor
Abort
Undef
System
User(Thread)
System (Handler)
メモリマップ
未規定
定義済み
Flash
基本外付け
基本内蔵
割り切り!
簡単!
高性能!
7
STM32シリーズラインナップ
各種コアとシリーズの対応
M3
M4
M0
M3
M4
M0+
M3
M4
http://www.st.com/web/en/catalog/mmc /FM141/SC1169
M7
2015年4月1日
ST社Webサイトより抜粋
8
Cortex-Mのラインナップ比較
システム機能概要
M0
M0+
M3/M4
M7
スリープモード
Yes
Yes
Yes
Yes
WIC
Yes
Yes
Yes
Yes
SVC、PendSV
Yes
Yes
Yes
Yes
-
0 or 8
0 or 8
0 or 8 or 16
HardFault
HardFault
HardFault
+3設定
HardFault
+3設定
フォールトステータスレジスタ
-
-
Yes
Yes
ビットバンド
-
-
オプション
オプション
L1キャッシュ
-
-
-
最大64KB(I&D)
TCM(密結合メモリ)
-
-
-
最大1MB(I&D)
MPU(オプション)
フォールト/例外ハンドラ
http://www.arm.com/ja/products/processors/cortex-m/cortex-m0.php
http://www.arm.com/ja/products/processors/cortex-m/cortex-m0plus.php
http://www.arm.com/ja/products/processors/cortex-m/cortex-m3.php
http://www.arm.com/ja/products/processors/cortex-m/cortex-m4-processor.php
http://www.arm.com/ja/products/processors/cortex-m/cortex-m7-processor.php
2015年4月1日 ARM社Webサイトより抜粋
9
Cortex-Mのラインナップ比較
最大パフォーマンス比較
1MHzあたりの処理量(CoreMark値)
http://www.eembc.org/coremark/index.php 2015年4月1日
EEMBC Webサイトより抜粋
10
Cortex-Mの命令セット
命令セット:Cortex-Mの命令セットThumb-2
Cortex-MではThumb-2命令をサポート
•
ARM命令セット
Thumb命令セット
•
Thumb-2命令セット 16ビット+32ビット命令混在
•
32ビット命令
16ビット命令
ARM7からの伝統的な命令セット
• よく使う命令は16
bit、複雑な命令は32bitで高効率を実現
• Cortex-Mのラインナップごとにサポート命令セットは異なる
12
命令セット:Cortex-Mの命令セットThumb-2
同じコードをコンパイルして結果を比較
int gcd(int a, int b)
{
while (a != b)
{
if (a > b)
a = a - b;
else
b = b - a;
}
return a;
}
最大公約数を求める関数
ARM、Thumb、Thumb2でビルド
13
命令セット:Cortex-Mの命令セットThumb-2
同じコード(最大公約数を求める関数)をコンパイルして結果を比較
Thumb命令セット
ARM命令セット
gcd:
gcd:
??gcd_0:
0x148:
0x14c:
0x150:
0x154:
0xe1500001
0x0a000003
0xe1510000
0xa0411000
CMP
BEQ
CMP
SUBGE
R0, R1
??gcd_1
R1, R0
R1, R1,
0x158: 0xb0400001
SUBLT
R0, R0,
0x15c: 0xeafffff9
B
gcd
0x160: 0xe12fff1e
BX
LR
R1
Thumb-2命令セット
0x4288
0xd004
0x4281
0xbfac
0x1a09
CMP
BEQ.N
CMP
ITE
SUBGE
R0, R1
??gcd_1
R1, R0
GE
R1, R1,
0x92: 0x1a40
SUBLT
R0, R0,
0x94: 0xe7f8
B.N
??gcd_0
0x96: 0x4770
BX
LR
??gcd_0
0x14a: 0x1a40
SUBS
R0, R0,
0x14c:
0x14e:
0x150:
0x152:
0x154:
CMP
BEQ.N
CMP
BLT.N
SUBS
R0, R1
??gcd_2
R1, R0
??gcd_1
R1, R1,
0x156: 0xe7f9
B.N
??gcd_0
0x158: 0x4770
0x15a: 0x0000
BX
MOVS
LR
R0, R0
0x4288
0xd003
0x4281
0xdbfa
0x1a09
R0
??gcd_2:
gcd:
??gcd_0:
0x88:
0x8a:
0x8c:
0x8e:
0x90:
B.N
R1
??gcd_0:
R0
??gcd_1:
0x148: 0xe000
??gcd_1:
ARM
gcd(バイト)
Thumb
28
Thumb-2
20
16
R0
R1
コード効率が高い
??gcd_1:
14
Cortex-Mプロセッサファミリごとのサポート命令
Cortex-Mに続く数字が大きくなるほど、多くの命令をサポート
浮動小数点演算
DSP(SIMD,高速加算乗算)
アドバンストデータ処理
ビットフィールド処理
基本データ処理
I/Oハンドリング
M0/M0+
M3
M4
M7
M4
FPU
M7
FPU
15
Cortex-Mプロセッサファミリの命令比較
命令セット概要
M0/M0+
シングルサイクル乗算
M3
M4
M7
Yes
Yes
Yes
Yes
ハードウェア除算
-
Yes
Yes
Yes
アドバンストメモリアクセス
-
Yes
Yes
Yes
アドバンスト分岐サポート
-
Yes
Yes
Yes
排他アクセス
-
Yes
Yes
Yes
SIMD DSP
-
-
Yes
Yes
サチュレーションサポート
-
一部
フル
フル
浮動小数点演算(オプション)
-
-
単精度
単精度/倍精度
16
Cortex-Mプロセッサファミリの命令比較
浮動小数点除算の例
元のCコード
M4F:8命令
M3:44命令
M0:171命令
コンパイラが自動的にコア搭載する命令を有効活用
17
Cortex-Mのレジスタ
Cortex-Mのレジスタ構成
CPUレジスタ
MSP
PSP
R0
R1
R2
R3
R4
R5
R6
R7
R8
R9
R10
R11
R12
R13(SP)
R14(LR)
R15(PC)
xPSR
汎用的に使えるレジスタ R0~R12
さらに、R0~R7までを下位レジスタ
R8~R12までを上位レジスタと呼ぶ。
R0~R7までが16ビット命令で
自由に使えるレジスタ
R13はスタックポインタとして使用。
2つあり、切り替えて使用することができる。
R14は関数の返りアドレスを保存するリンクレジスタとして使用。
R15はプログラムの実行アドレスを示すPCに使用。
xPSRは実行状態を示す。演算結果フラグ、割り込み番号、使用す
る命令セット(Thumb系か否か)。
NMIとフォルトハンドラ以外の割り込みの許可・禁止を制御する
PRIMASK
CONTROL
FAULTMASK
BASEPRI
M3/M4/M7のみ
使用するスタックの指定、特権/ユーザ・レベル。
NMI以外の割り込みの許可・禁止を制御する
指定優先度以下の割り込みの許可・禁止を制御する
19
Cortex-Mのレジスタ構成
ステータスレジスタ
31 30 29 28 27 26 25 24 23
xPSR N
Z
C
V
Q
APSR N
Z
C
V
Q
ICI/IT
T
16 15
10 9 8 7
ICI/IT
IPSR
EPSR
•
0
Esception Number
Exception Number
ICI/IT
T
ICI/IT
アプリケーションプログラムステータスレジスタ APSR – 演算結果のフラグ
•
割り込みプログラムステータスレジスタ IPSR – 割り込み番号
•
実行プログラムステータスレジスタEPSR – 実行状態bit
各レジスタは個別にも、まとめても(xPSR)アクセス可能
20
Cortex-Mのレジスタ構成
コントロールレジスタ
31
CONTROL
2
1
0
Reserved
• bit [0] でスレッドモード時の特権を設定
— 0: スレッドモードは特権あり
— 1: スレッドモードは特権なし.
• bit [1] はスタックを選択
— 0: メインスタックポインタを使用
— 1: スレッドモードのときは、プロセススタックポインタを使用。
MRS命令でREAD、MSR命令でWRITE。
特権がないとアクセスできない。
21
Cortex-Mの関数コールとレジスタ
関数のジャンプ時には、レジスタ操作が行われる
•
•
•
•
引数は R0,R1,R2,R3を利用(5つ目からスタックに)
返り値はR0を利用
ジャンプするときには、BL命令
戻る時はいろいろPC(R15)を操作する命令
• たとえば、BX命令、POP命令
R0
R1
R2
R3
R4
R5
int f1(int a ) {
return a+1;
}
int main (void) {
・・・
t = f1(10);
Cコード
f1:
ADDS
#1
BX
R6
R0, R0,
LR
R7
R8
R9
main:
・・・
BL
R10
R11
f1
コンパイル結果
R12
R13 (SP)
R14 (LR)
R15 (PC)
CPSR
22
Cortex-Mの関数コールとレジスタ
実際に動作を見てみる
PC=0x200_01FA0
LR= 0x200_01F91
戻りアドレス=0x20001FA4
BLでジャンプ
BL命令は LR(R14)レジスタに戻りアドレスを
保存し、PCを関数にセットする
PC=0x20001F98
LR= 0x20001FA5
23
Cortex-Mの関数コールとレジスタ
実際に動きを見てみる:関数からの戻り
PC=0x20001F9A
LR= 0x20001FA5
BXでジャンプ
BX命令は LR(R14)レジスタで指
定されるアドレスにジャンプ
PC=0x20001FA4
LR= 0x20001FA5
*Thumb命令では、ジャンプ時にLRのアドレスのLSBが常に1にセットされる
24
ARMのレジスタとSTのレジスタ
ARMマイコンはARM CPUレジスタと周辺レジスタがある
ARM
ST
25
Cortex-Mの割込みハンドリング
NVIC(内蔵割込みコントローラ)
Cortex-Mプロセッサは割込みコントローラを内蔵している
•
•
•
レジスタの退避
割込み優先度ハンドリング
ネスト割込みのハンドリング
Cortex-M
NMI
NVIC
各種割込み
Core
システム例外
SysTick
タイマーペリフェラル
27
ベクタテーブルの記述
4バイト単位で、割込みハンドラのアドレスを記述
*先頭だけは、スタックのアドレスを指定
スタックアドレス
Vector No.
Vector Offset
例外& 割り込み
値(例)
00
0x00
Stack Top
sfe (CSTACK)
01
0x04
Reset
__iar_program_start
02
0x08
NMI
Default Handler
03
0x0C
Hard Fault
Default Handler
04
0x10
Memory Management
05
0x14
Bus Fault
Default Handler
06
0x18
Usage Fault
Default Handler
07~10
0x1C~0x28
Reserved
0
11
0x2C
SVCall
Default Handler
12
0x30
Debug Monitor
Default Handler
13
0x34
Reserved
0
14
0x38
PendSV
Default Handler
15
0x3C
SysTick
Default Handler
16 ~ 255
0x40~0x3FC
External Interrupts
Interrupt Handlers
RESETハンドラアドレス
Default Handler
外部割込みのハンドラアドレス
28
ベクタテーブルの比較
クラシックARMおよびCortex-R/Aとの比較
ARM9 ( + Cortex-R/A)
__vector:
ARM
LDR
LDR
LDR
SWI/SVC)
LDR
LDR
DCD
LDR
LDR
PC,Reset_Addr
PC,Undefined_Addr
PC,SWI_Addr
; Reset
; Undefined instructions
; Software interrupt
PC,Prefetch_Addr
PC,Abort_Addr
0
PC,IRQ_Addr
PC,FIQ_Addr
;
;
;
;
;
Cortex-M
#pragma location = ".intvec"
const intvec_elem __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) },
__iar_program_start,
Prefetch abort
Data abort
RESERVED
IRQ
FIQ
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
0,
0,
0,
0,
SVC_Handler,
DebugMon_Handler,
0,
PendSV_Handler,
SysTick_Handler,
DATA
Reset_Addr:
Undefined_Addr:
SWI_Addr:
Prefetch_Addr:
Abort_Addr:
IRQ_Addr:
FIQ_Addr:
DCD
DCD
DCD
DCD
DCD
DCD
DCD
__iar_program_start
Undefined_Handler
SWI_Handler
Prefetch_Handler
Abort_Handler
IRQ_Handler
FIQ_Handler
//Device specified interrupt handler
InterruptHandler0
InterruptHandler1
アセンブラ命令
(割込みハンドラにジャンプ)
InterruptHandler240
};
C言語(ハンドラのアドレス指定)
29
SysTickタイマーで割込み動作確認
SysTickを有効にして確認
static int tick = 0;
void SysTick_Handler(void)
{
割り込みハンドラはCの関数。
tick++;
ハンドラと関数に差はない
}
int main( void )
{
SysTick->LOAD = 0x0000FFFF; //←リロードレジスタの値をセット
SysTick->VAL
= 0;
// ←初期値をセット
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk
|
SysTick_CTRL_ENABLE_Msk;
//← コアクロックで割込み有効でスタート
__enable_interrupt();
while (1)
{
//SysTick_Handler();
delay();
}
}
30
SysTickタイマーで割込み動作確認
EWARMのデバッガ機能で確認
割り込みハンドラの先頭
LRは割込みを意味する
0xFFFF_FFxx
PCはハンドラへ
31
SysTickタイマーで割込み動作確認
自動的にスタックにレジスタが退避される
0x0000_0000側
R0:
R1:
R2:
R3:
R12:
LR:
PC:
割込み前の
LRの値
割り込み発生の
アドレス
CPSR
使用スタック
使用スタック
0xFFFF_FFFF側
表示-スタック-スタック1
スタックの表示可能
32
SysTickタイマーで割込み動作確認
割込みハンドラを通常の関数として呼んでみる
コメントを外して
メイクしてデバッグ
33
SysTickタイマーで割込み動作確認
割込みハンドラを通常の関数として呼んでみる(結果)
関数から呼んだ場合
LR = 0x080001C1
SysTick_Handler:
0x800019e: 0x4815
[0x80001f4] tick
0x80001a0: 0x6801
0x80001a2: 0x1c49
0x80001a4: 0x6001
}
0x80001a6: 0x4770
int main( void )
{
main:
- - - SysTick_Handler();
0x80001bc: 0xf7ff 0xffef
0x800019e
割込みから呼ばれた場合
LR = 0xFFFFFFE9
LDR.N
R0, [PC, #0x54]
LDR
ADDS
STR
R1, [R0]
R1, R1, #1
R1, [R0]
BX
LR
BL
SysTick_Handler
;
;
34
SysTickタイマーで割込み動作確認
割込みハンドラでのLRの値(EXC_RETURN)
割込みを抜ける際のスタックポインタ、多重割込み、FPUなどにより異なる
MSP(メイン)
PSP(プロセス)
割り込み時
使用
×
その他
使用可能
使用可能
• CONTROLレジスタの設定で使用スタックの変更が可能
LRの値
0xFFFF_FFF1
多重割込み
0xFFFF_FFF9
通常状態への復帰時にMSPを使用
0xFFFF_FFFD
通常状態への復帰時にPSPを使用
0xFFFF_FFE1
多重割込み(FPU状態)
0xFFFF_FFE9
通常状態への復帰時にMSPを使用(FPU状態)
0xFFFF_FFED
通常状態への復帰時にPSPを使用(FPU状態)
35
スタートアップ処理
Cortex-Mのリセット動作
Cortex-Mでは起動時にベクタテーブルの内容を元に初期化される
ベクタ先頭
0x0000_0000
スタックの先頭アドレス
リセットハンドラアドレス
NMIハンドラアドレス
リセットされるとCPUは
メモリから2ワード読み出す。
最初のデータでスタックポインタをセット。
2つ目のデータにPCをセット。
リセット
スタック
37
EWARM+Cortex-Mの起動動作
参照
ジャンプ
Cortex-M0/M3/M4
Vector Table:
IAR DLIB
ランライム
ライブラリの
コード
ただし
上書き可能
thumb¥vector_table_M.s
or thumb¥cstartup_M.c
デフォルトプログラムエントリ:
thumb¥cstartup_M.s
or thumb¥cstartup_M.c
main()前の初期化:
thumb¥cmain.s
ユーザコード
User’s Application:
例外& 割り込み
値
0x00
Stack Top
sfe (CSTACK)
01
0x04
Reset
__iar_program_start
02
0x08
NMI
Default Handler
03
0x0C
Hard Fault
Default Handler
04
0x10
Memory Management
Default Handler
05
0x14
Bus Fault
Default Handler
06
0x18
Usage Fault
Default Handler
07~10
0x1C~0x28
Reserved
0
11
0x2C
SVCall
Default Handler
12
0x30
Debug Monitor
Default Handler
13
0x34
Reserved
0
14
0x38
PendSV
Default Handler
15
16 ~ 255
0x3C
0x40~0x3FC
SysTick
External Interrupts
Default Handler
Interrupt Handlers
Vector No.
Vector Offset
00
__iar_program_start:
bl __iar_init_core
bl __iar_init_vfp
bl __cmain
; optional
; optional, enable VFP, thumb¥fpinit_M.s
__cmain:
bl __low_level_init
bl __iar_data_init3
bl main
; low_level_init.c
; initialize data sections, init¥data_init3.c
int main (void) { …… }
void xxx_InterruptHandler (void) { …… }
38
初期化処理のデバッグ
デバッグのオプションを変更することで、main以前のデバッグ可能
チェックを外す
39
初期化処理のソースコード
EWARMインストールフォルダに初期化処理のソースコードがる
EWARMのインストールフォルダ
#pragma location = ".intvec"
const intvec_elem __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) },
__iar_program_start,
NMI_Handler,
HardFault_Handler,
};
void __cmain( void );
__weak void __iar_init_core( void );
__weak void __iar_init_vfp( void );
Reset
#pragma required=__vector_table
void __iar_program_start( void )
{
__iar_init_core();
__iar_init_vfp();
__cmain();
}
__cmain:
bl
cmp
beq
bl
?l1:
MOVS
BL
line
BL
BL
__low_level_init
r0,#0
?l1
__iar_data_init3
変数の初期化
r0,#0
__iar_argc_argv
; No parameters
; Maybe setup command
main
exit
main
40
リンカ設定でメモリ配置コントロール
ILINKの基本概念・キーワード
EWARMのリンカはILINK
詳細使用方法はC/C++開発ガイドを参照
42
ILINKの基本概念・キーワード
GUIの設定項目
プロジェクトオプション > リンカ > 設定
ベクタテーブル、ROM/RAM領域、スタックサイズの変更が可能
43
ILINKの基本概念・キーワード
リンカの働き
領域(Region)を指定して、そこにセクションやブロックを配置
ROMの特定の
アドレスに配置
Memory領域
Region
0x00000000-0x0000FFFF
IARの標準セクション
.intvec
.text
place in
ROM
に配置
.data_init
.rodata
.data
Region
0x20000000-0x2000FFFF
place in
ブロック(スタック)
RAM
に配置
ブロック(ヒープ)
割り込みベクター
コード
変数の初期化データ
constデータ
変数
44
ILINKの基本概念・キーワード
リンカ設定ファイルのキーワード紹介
• region
メモリ上の領域を指定します。
• block
サイズを指定します
• section
プログラムのセクション
• initialize
初期化方法の指定
• do no initialize 初期化しない領域の指定
• place
regionにblockやsectionを配置
• rw(readwrite), ro(readonly)の属性を指定
ILINKの基本概念・キーワード
EWARMの基本セクション
•
.bss
:0初期化する変数
•
.data
:0以外で初期化される変数
•
.data_init
•
.intvec
: ベクタ
•
.noinit
:初期化しない変数
•
.rodata
: readonlyの変数
•
.text
: プログラム
•
.textrw
: __ramfuncを使った時のコード
•
.textrw_init
: .textrwの初期化データ
: .dataセクションの初期化データ
*詳細はIAR C/C++ 開発ガイドのセクションリファレンスを参照
実際に動作をみてみる(関数を配置)
ファイルfunc.cのLED絡みの関数を特定領域に配置
0x00000000
IROM
0x00050000
ROMLED
0x00FFFFF
void set_LED_port(void)
void LED_Handler(void)
0x20000000
RAM
0x2000FFFF
47
実際に動作をみてみる(関数を配置)
C言語ソースコードでの指定
pragmaでセクション定義。
EWARMではセクション定義は
#pragma location=“XXXX”
EWARMではセクションを参照するときに
#pragma section=“XXXX”
とななる。
48
実際に動作をみてみる(関数を配置)
実際にセクションを指定
#pragma location="LED"
void set_LED_port(void )
{
printf("initialize LED port¥n");
}
#pragma location="LED"
void LED_Handler(void)
{
Port0 != Port0;
}
set_LED_portがセクション”LED”に割当
LED_Handlerがセクション”LED”に割当
49
実際に動作をみてみる(関数を配置)
リンカ設定ファイル(抜粋)
0x00000000から0x0004FFFFをIROM_region
define region IROM_region
=
mem:[from __ICFEDIT_region_IROM1_start__ to 0x0004FFFF ];
define region ROMLED_region= mem:[from 0x00050000 to __ICFEDIT_region_ROM_end__];
0x00050000から0x000FFFFFをROMLED_region
place in IROM_region
{ readonly }except { section LED };
セクションLEDを除く、readonlyをROM_regionに配置
place in ROMLED_region
{ readonly section LED };
セクションLEDのreadonlyをROMLED_regionに配置
50
実際に動作をみてみる(関数を配置)
ビルド結果のmapファイル
プロジェクトオプション > リンカ > リスト > リンカマップファイルの表示
Outputフォルダに生成されるマップファイルをダブルクリックで表示
Codeは関数を示す
関数が奇数アドレスは、Thumb命令。
(Cortex-MはすべてThumb命令。)
51
実際に動作をみてみる(変数を配置)
RAM2に図のように4つの変数を配置
0x00000000
ROM
0x000FFFFF
0x20000000
0x20004000
0x2000FFFF
RAM
int
int
int
int
mydat1[10];
mydat2[10];
mydat3[5];
mydat4[5];
RAM2
52
実際に動作をみてみる(変数を配置)
実際にセクションを定義
ひとつひとつ変数にセクションを割り当て
#pragma location="MYDAT"
__root int mydat1[10];
#pragma location="MYDAT"
__root int mydat2[10];
#pragma default_variable_attributes = __root
int mydat3[5];
int mydat4[5];
#pragma default_variable_attributes =
@ "MYDAT"
まとめて変数に属性をつける
このとき__rootもpragma側でつけること
53
実際に動作をみてみる(変数を配置)
リンカ設定ファイル
define region RAM_region
define region RAM2_region
place in RAM_region
= mem:[from __ICFEDIT_region_RAM_start__
= mem:[from 0x20004000
{ readwrite,
to 0x20003FFF];
to __ICFEDIT_region_RAM_end__];
block CSTACK, };
place in RAM2_region { readwrite section MYDAT};
RAM2_regionにセクションMYDATの
readwriteデータを配置
54
実際に動作をみてみる(変数を配置)
MAPファイルを確認
#pragma location="MYDAT"
__root int mydat1[10];
#pragma location="MYDAT"
__root int mydat2[10];
#pragma default_variable_attributes = __root
int mydat3[5];
int mydat4[5];
#pragma default_variable_attributes =
define region RAM2_region
=
mem:[from 0x20004000 to _ICFEDIT_region_IRAM1_end__];
place in RAM2_region { readwrite
mydat1
mydat2
mydat3
mydat4
0x20004000
0x20004028
0x20004050
0x20004064
0x28
0x28
0x14
0x14
@ "MYDAT"
section MYDAT};
Data
Data
Data
Data
Gb
Gb
Gb
Gb
main.o
main.o
main.o
main.o
[1]
[1]
[1]
[1]
55
実際に動作をみてみる(変数を手動初期化)
初期化つき変数にセクション定義
初期化つき変数にセクションを割り当て
#pragma location="MYDAT"
__root int mydat1[10] = {0,1,2,3,4,5,6,7,8,9,};
#pragma location="MYDAT"
__root int mydat2[10] = {10,11,12,13,14,16,17,18,19};
初期化つき変数にセクションを割り当て
56
実際に動作をみてみる(変数を手動初期化)
初期化ルーチンの作成
プログラム中でセクション名を参照する場合には
#pragma sectionで明示する。
#pragma section="MYDAT"
#pragma section="MYDAT_init"
void init_MYDAT( ) {
int i;
unsigned char *psrc, *pdest;
変数はMYDATというセクションになる。
初期化データはMYDAT_initというセクションにる。
pdest = __section_begin("MYDAT");
psrc = __section_begin("MYDAT_init");
for (i=0; i < __section_size("MYDAT"); i++ ) {
*pdest = *psrc;
pdest++;
psrc++;
}
セクションMYDATの先頭アドレスを
__section_beginで取得
セクションMYDAT_initの先頭アドレスを
__section_beginで取得
}
セクションMYDATのサイズを
__section_sizeで取得
57
実際に動作をみてみる(変数を手動初期化)
リンカ設定ファイルでの指定
この領域の初期化は自動に行う
initialize by copy { readwrite } except {section MYDAT};
initialize manually with packing=none { readwrite section MYDAT};
place in RAM2_region { readwrite
section MYDAT};
この領域の初期化は手動で行う
+
初期化データの圧縮はしない
58
実際に動作をみてみる(変数を手動初期化)
マップファイルでの確認
initialize manually { readwrite section MYDAT};の場合
************************************
*** INIT TABLE
***
initialize by copy { readwrite };の場合
******************************************
*** INIT TABLE
***
Address Size
------- ---Zero (__iar_zero_init3)
1 destination range, total size 0x54:
0x20000030 0x54
Address Size
------- ---Zero (__iar_zero_init3)
1 destination range, total size 0x54:
0x20000030 0x54
Copy (__iar_copy_init3)
1 source range, total size 0x50:
0x000019dc 0x50
1 destination range, total size 0x50:
0x20004000 0x50
Copy (__iar_copy_init3)
1 source range, total size 0x30:
0x00001be4 0x30
1 destination range, total size 0x30:
0x20000000 0x30
ない
mydat1 0x20004000 0x28 Data Gb main.o [1]
mydat2 0x20004028 0x28 Data Gb main.o [1]
ある
Copy (__iar_copy_init3)
1 source range, total size 0x30:
0x00001bf8 0x30
1 destination range, total size 0x30:
0x20000000 0x30
59
実際に動作をみてみる(変数を手動初期化)
初期化関数前後の変数の値を比較
コード
for ( i=0; i< 10; i++){
printf("BEFORE No%d - %d¥n", i, mydat1[i]);
}
init_MYDAT( );
初期化関数を実行
for ( i=0; i< 10; i++){
printf("AFTER No%d - %d¥n", i, mydat1[i]);
}
printf出力結果
表示>ターミナルI/O
initialize LED port
BEFORE No0 - -842150451
BEFORE No1 - -842150451
BEFORE No2 - -842150451
BEFORE No3 - -842150451
BEFORE No4 - -842150451
BEFORE No5 - -842150451
BEFORE No6 - -842150451
BEFORE No7 - -842150451
BEFORE No8 - -842150451
BEFORE No9 - -842150451
AFTER No0 - 0
AFTER No1 - 1
AFTER No2 - 2
AFTER No3 - 3
AFTER No4 - 4
AFTER No5 - 5
AFTER No6 - 6
AFTER No7 - 7
AFTER No8 - 8
AFTER No9 - 9
60
Cortex-Mへの移行時の注意点
Cortex-Mへの移行時の注意点
アーキテクチャにより、仕様が異なる項目に注意する
• スタックサイズ
• intデータのサイズ
• 構造体のパッキング
62
スタックサイズ
8bit、16bitマイコンと比較するとスタック使用量は多い
全レジスタ汎用レジスタ+PC+STACK+CPSRを退避した際の例
Cortex-M
16bitマイコンの例
68?バイト
14?バイト
EWARMでは2種類のスタック解析機能で使用量を解析可能
• 静的なスタック解析(メイク時)
• 動的なスタック解析(デバッグ時)
63
スタックサイズ
静的なスタック解析(メイク時) :オプション設定
プロジェクトを選択し、✓をダブルクリック
[リンカ]-[アドバンスド]-[スタックの使用量解析を有効にする]
1
2
4
3
5
64
スタックサイズ
静的なスタック解析(メイク時):マップファイルに表示
メイクでマップファイルに解析結果表示
Call Graph Root Category
-----------------------interrupt
Program entry
Max Use
------0
232
Total Use
--------0
232
Program entry
"__iar_program_start": 0x0000058d
Maximum call chain
"__iar_program_start"
"__cmain"
"main"
"dhry_main"
"Proc_1"
"Proc_6"
"Func_3"
232 bytes
0
0
8
192
16
16
0
Mainの実行されるパスでの
スタック使用量
interrupt
"__default_handler" in vector_table_M.o [4]: 0x00000473
Maximum call chain
"__default_handler" in vector_table_M.o [4]
0 bytes
0
ハンドラの実行されるパスでの
スタック使用量
65
スタックサイズ
静的なスタック解析(メイク時):解析サポート機能
•
関数ポインタなどを使うと、自動では追えない
•
#pragma calls=XX,YY を使って手動指定
void Fun1(), Fun2();
void Caller(void (*fp)(void))
{
#pragma calls = Fun1, Fun2
(*fp)();
この関数はFun1,Func2が呼ばれる
}
•
解析のスタート関数を個別指定したい
#pragma call_graph_root
void delay_time(int number){
・・・
}
66
スタックサイズ
動的なスタック解析(デバッグ時):ツールオプション設定
[ツール]-[オプション]
[スタック]-[グラフィカルスタック表示・・・]を有効
1
2
4
3
67
スタックサイズ
動的なスタック解析(デバッグ時):表示
[表示]-[スタック]-[スタック1]
1
2
3
68
スタックサイズ
動的なスタック解析(デバッグ時):実行結果表示
灰色は使用した量
緑のバーは現状値
マウスをあてると
詳細が表示
69
intデータ型のサイズ
intデータ型のサイズは、マイコン・コンパイラにより異なる
EWARM
16ビットマイコン
signed char
8
8
unsigned char
8
8
signed short
16
16
unsigned short
16
16
signed int
32
16
unsigned int
32
16
signed long
32
32
unsigned long
32
32
signed long long
64
32
unsigned long long
64
32
70
intデータ型のサイズ
マイコンにより、結果が異なる例
unsigned short
c=0xFFFF;
int gg(unsigned short a, unsigned short b)
{
if ( c == ( a | ~b) ) {
return 0;
} else {
return 1;
}
}
int main( void ) {
int t;
x =0で、yが0, c=0xFFFFの時のprintfの出力
16 bit
result=0
32 bit
result=1
t= gg(0, 0 );
printf("result=%d¥n", t);
return 0;
}
71
構造体のパッキング
構造体のパッキングによる差
struct S1 {
char
s1;
int
s2;
char
s3;
int
s4;
char
s5;
} A[10];
struct S2 {
char
s1;
char
s3;
char
s5;
int
s2;
int
s4;
}
B[10];
Entry
Address
Size(hex)
Size(Dec)
Type
Object
A
0x20000000
0xc8
200
Data Gb
main.o [1]
B
0x200000c8
0x78
120 ▲40%
Data Gb
main.o [1]
struct S1での状況
struct S2での状況
s1
s2
5
s5
s3
s4
s3
s2
s4
s1
3
s5
4バイト
4バイト
72
解析ツールを使用して品質向上
解析ツールを使用して品質向上
IARシステムズの提供する解析アドオン製品を使用して品質向上
• 静的解析アドオン機能 C-STAT
• MISRA-C 2004/2008C++/2012のチェック
• CWE / CERTルールに準拠した脆弱性のチェック
• 動的解析アドオン機能 C-RUN
• 実行時の数値演算エラーの検出
• 不適切なメモリ利用の検出
※C-RUN/ C-STATはEWARM製品版に対するアドオン製品となります。
74
静的解析アドオン機能C-STAT
実動作不要の静的解析で、潜在的なコードエラーを検出
ソースコードレベルにおいて潜在的なエラーやバグを
EWARM上で発見。
例えばメモリリーク・アクセス違反・算術演算の
エラー・配列や文字列のオーバーランといった
潜在的なコードエラーを発見でき、
アプリケーションの誤動作を未然に防止。
主な機能
• C , C++ 言語に対応
• MISRA C:2004, MISRA C++:2008, MISRA C:2012に対応
• CWE や CERT C/C++といった基準に基づく100以上のルールに沿ったチェック
• 直感的で簡単に使える設定
• 任意でコーディング規約単位または個別のルール単位でチェック
• IAR Embedded Workbenchとシームレスに統合
• 短時間で解析
• ARM用IAR Embedded Workbenchバージョン7.40より利用可能
75
簡単に使える「C-STAT」
EWARMのオプションで解析したいチェックルールを選択するだけ
[静的解析]を選択
[C-STAT check]をクリック
プロジェクトを右クリックし
[オプション…]を選択
CWE/CERTをベースに
動作時不良リスクをチェック
MISRA C
コーディングガイド
準拠チェック
チェック項目選択画面
76
「C-STAT」の実行
EWARMのオプションメニューで選択するだけ
プロジェクトを
右クリック
[C-STAT]静的解析
プロジェクトを解析
数分でC-STATメッセージが表示
77
動的解析アドオン機能C-RUN
デバッグ実行時に、実際に発生した潜在エラーを検出
事前に設定したチェック項目を対象にデバッグ実行中に、
リアルタイムにチェックを行い、違反した挙動を
検出し、EWARM上で通知。
実装フェーズから問題を検出することで、後段での
テスト・修正工数を削減し、品質向上・納期短縮を実現
•
•
•
•
•
•
•
•
•
•
•
•
•
•
主な機能
C, C++言語に対応
直感的で簡単に使える設定
包括的かつ詳細な実行時のエラー情報
エラーが見つかった場所のコールスタック情報
エディタ上でのコード位置を表示やグラフィカルな表示
自由度の高いエラー情報の管理
配列や他のオブジェクトが境界内に正しくアクセスしていることを保証する境界チェック
バッファオーバーフローの検出
データのキャスト時の、値の変化を検出
算術計算時の値のチェック
シフト演算のビット損失を検出
ヒープやメモリリークに関するチェック
ARM用IAR Embedded Workbenchバージョン7.20以降で利用可能
78
動的解析アドオン機能C-RUN
デバッグ実行時に、実際に発生した潜在エラーを検出
コンパイラ開発者による高効率
IDE tools
Build tools
IAR C-SPY
Debugger
Editor
IAR C/C++ Compiler
Simulator driver
Project manager
Assembler
Hardware system drivers
Library builder
Linker
Librarian
完全に統合された
動的解析
Power debugging
RTOS plug-ins
詳細かつ柔軟な
動的エラー情報
79
簡単に使える「C-RUN」
EWARMのオプションで解析したいチェックルールを選択するだけ
※ビルド時にチェックコードが実行コードに埋め込まれる
[ランタイム解析]を選択
[有効化]をチェック
チェックしたい項目をチェック
80
「C-SRUN」の実行
EWARMのデバッグ実行中に自動的に検出される
発生したソース位置
発生した違反
発生したPC位置
発生したコア
(マルチコア対応)
データ値の表示
値0x000001f4を0xf4にした
コールスタックで、mainから、convを呼んだ中で発
生したことを示す。
81
まとめ
まとめ

Cortex-Mの特徴を理解することで、レジスタや命令セットの読み方
を習得できる
 割込みハンドラやベクタテーブルは、従来のARMコアから変更となっ
ている。
 初期化処理やリンカ設定はEWARM独自の記述となり、既存のものを
参考にカスタマイズしていく。
 マイコンアーキテクチャごとに動作の異なるコーディングに注意する
 静的解析ツール、動的解析ツールを使用することで、不具合の早期発
見、品質向上につながる
83
本資料について
本資料取り扱い上の注意
本資料は2015年4月1日時点の情報を基に作成されており、将来変更の可能性
のあるものです。あわせてご紹介する設定や機能に関連して、動作保証をお約束す
るものではございませんので、ご了承ください
本資料で提供している情報は、ご利用されている方のご判断・責任においてご使用
ください。提供した情報に関連して、ご利用される方が不利益等を被る事態が生じ
たとしても、弊社及び執筆者は一切の責任を負いかねますので、ご了承ください。
本資料の内容に関する弊社または各社へのお問合せはご遠慮ください。
本資料及びデータの再配布・無断転用・転載等はご遠慮ください。
85
商標について
• IAR Systems, IAR Embedded Workbench, C-SPY, C-RUN, C-STAT,
visualSTATE, Focus on Your Code, IAR KickStart Kit, I-jet, I-scope, IAR, お
よび IAR Systems のロゴタイプはIAR Systems ABが所有する商標または登録
商標です。
• ARMおよびCortexは、ARM Limited(またはその子会社)のEUまたはその他の
国における登録商標です。 ARMおよびThumbは、ARM Limited(またはその子
会社)のEUまたはその他の国における商標です。 CoreSightは、ARM Limited
(またはその子会社)のEUまたはその他の国における商標です。 All rights
reserved.
• STM32は、STマイクロエレクトロニクスの登録商標です。
• その他、本資料中の製品名やサービス名は全てそれぞれの所有者に属する商標ま
たは登録商標です。
86