Press "Enter" to skip to content

マイコンへのプログラムの書き込みの仕組み(JTAG, SWD, シリアル)

Arduinoを使わず、自分でマイコンを選定し組込みシステムを実装しようと考えた時に避けて通れないJTAGやSWD。プログラムの書き込みといった初歩的なところを支える技術であるにも関わらずネットにはあまり説明してくれているサイトが無い印象です。またArduinoはなぜJTAG,SWDを使わずに済んだのかについて調べるのにも少し苦労します。そこで「プログラムの書き込み」に関していろいろ調べてみました。

プログラムはどこに格納されるか

マイコンの主記憶にはRAM (Random Access Memory)とROM (Read Only Memory)の2つがあり、プログラムはROMに格納されます

これは

  • RAMは読み込み/書き込みのいずれも高速でできるため、処理中のデータの格納に利用
  • ROMは書き込みに少し難があるためプログラムなどの読み込み専用のデータの格納に利用

という形で使い分けがされていることに起因するようです。

(ROMは Read Only と銘打っていますが、後述するように昔使われていたマスクROM以外は書き込みが全くできないわけではありません。)

マクスROM / EPROM/ EEPROM / フラッシュメモリ

ROMはその内訳としてマスクROM, EPROM, EEPROM, フラッシュメモリの4種類に分けることができます。この TIの解説ページ に、ROMとRAMをまとめた表があります。

最近のマイコンはEEPROMとフラッシュメモリを使うことが多く、プログラムは特にフラッシュメモリに書かれることが多いようです

書き込みに難がある原因

先程ROMは書き込みに少し難があるためプログラムのような読み込み専用のものを格納する、と書きました。フラッシュメモリの書き込みは このブログ に説明があります。内容をまとめると

  • フラッシュメモリはブロック(ページ)ごとにデータを消去してからでないと書き込みができない

ということになるかと思います。RAMのようにピンポイントでの書き込みができないため、RAMよりも書き込みの自由度が下がります。

余談

マスクROMは物理配線なので一度配線をしたら変更が効きません。物理配線によるプログラミングはなんだか ENIAC を連想させます(ENIAC はパッチパネルがあったので書き換えができましたが。)

あとEPROMは紫外線消去をするというのが特徴的です。昔の半導体のパッケージには窓がついていて中身の半導体が見える状態のものもありました。この窓はまさに紫外線を照射するためのものです。


(↑ 物理配線によるプログラミング)


(↑ 紫外線照射のための窓がついたパッケージ)

マスクROMもEPROMも、最近はフラッシュメモリに置き換わっているので使う機会はほとんどないと思います。

ROMへアクセス

プログラムはROM(特に最近ではフラッシュメモリ)に書き込まれるということがわかりました。次に疑問になるのは、どうやってROMに書き込むかという話です。

アクセス方法1 : デバッグユニットを経由してアクセス

アクセス方法の1つは、デバッグユニットを使う方法です。


(引用元: https://www.arm.com/files/pdf/CoreSight_Datasheet.pdf
デバッグ用の回路は緑の Debug Bus (APB) で、そのバスのインターフェイス部分が Debug Access Point 。

デバッグといえばプログラムの特定の行で処理を止めてレジスタやメモリの値を読み込むといった処理を想像します。このようにCPUを止めたりメモリから値をとってきたりするのがデバッグユニットの仕事です(デバッグユニットは通常の計算処理を行うための回路とは別に用意されています)。

マイコンにプログラムを書き込む場合、PCから書き込むことが多いと思いますが、このデバッグユニットは外部機器との接続インターフェイスを持っていて、それがJTAG/SWDということになりそうです。

ただ、当然のことながらPCはJTAG,SWDのポートなど持っていません。そこで必要になるのが USB <-> JTAG, SWDの変換器であり、これがいわゆるデバッガ になります。

ARM の例

ARMの場合、CoreSight Debug Access Port (DAP) がデバッグユニットに該当するみたいです。デバッガは

  • Segger J-Link
  • Redlink
  • LPC-Link
  • ULINK
  • FT2232
  • ST-LINK

などいろいろあります。これらは互換性が無いので使うチップに合わせてデバッガを選ぶ必要があります。

最近は ARM Cortex-M を使ったマイコンならばどれでもデバッグできる DAPLink というものも登場しているようです。

アクセス方法2 : ブートローダを経由してアクセス

アクセス方法のもう1つは、ブートローダを経由してアクセスする方法です。この方法のメリットはデバッガが必要ないことです。Arduinoのように、単純にPCとUSB接続するだけで簡単にプログラムの書き込みができます。

ブートローダはシリアル通信(USB, UARTなど)から入ってきたデータをROMへ展開するためのプログラム です。なんだか特別なものに感じるかもしれませんが、実体としてはユーザが作るプログラムと全く同じです。

マイコンは通常、1つのプログラムしか書き込まれず1つのプログラムしか動かしません。一方でブートローダを使う場合はROMに

  • ブートローダ
  • ユーザの作成したプログラム

という2つのプログラムを書き込みます。ここが特徴的です。マイコンに電源が入るとブートローダがまず動き、条件に応じてシリアルから入力されたプログラムをROMに展開します。具体的な動作の手順は以下のようになります。Arduinoはパターン1です。

ブートローダからユーザプログラムへの処理の移行は、おそらくですがアセンブラの jump 命令を使っているのではないかと思います。

プログラムの共存

フラッシュメモリは書き込みの際、書き込みをする領域のページを一旦全部消去してから書き込みを行うと上で説明しました。そのため ブートローダとユーザプログラムの書き込むエリアが同じページに位置していた場合、ユーザプログラムを書き込む時ににブートローダを消去してしまう問題が発生します

これは原理的にそうなってしまうので、ブートローダとユーザプログラムの書き込むエリアを離すしか方法はありません。


(引用元: http://ww1.microchip.com/downloads/en/AppNotes/01094a.pdf

マイコンのリファレンスにはこういったメモリのアドレスの使い方を説明した図があります。この図を見ればわかるようにブートローダとユーザプログラムは異なるページに所属していることがわかります。
(あと 0x0200-0x03ff の部分は空きとなっていますが、そこにブートローダの一部を詰める形で書き込むとページを跨いでしまうためよくありません。)

ブートローダはどう書き込むか

ブートローダでブートローダは書き込めません。そのためブートローダはJTAG/SWDを使って書き込むしか方法はありません。

ただ、場合によってはチップを購入した時点でブートローダが書き込まれていることもあるので、実際にマイコンを使う場合にはあまり考える必要は無いかもしれません。

Arduinoのブートローダの実装

実際に Arduino のブートローダのプログラムを見てみます。
ArduinoCore-avr/bootloaders/atmega/ATmegaBOOT_168.c

コメントが多めでかつシンプルな実装になっているので初心者にも理解しやすい印象です。プログラムの書き込みに関する処理を追っていくと

  1. UART の初期化
  2. UART に送られてくるデータ(コマンド)を監視し、送られてきたコマンドに応じて処理を分岐
  3. 2番の処理を for ループで繰り返す。

という大きな流れになっていることがわかります。関係がありそうなコマンドに対する処理は以下のようになっています(以下、ブートローダ側からの視点で説明しています)。

コマンド 処理内容
‘P’ プログラムの書き込みモードに入る
‘Q’ プログラムの書き込みモードを出る(マイコンのリセット)
‘U’ 書き込みアドレスの指定(コマンドの後に2byteのアドレス値が来る)
‘d’ プログラムの書き込み(コマンドの後にデータが来る)
‘t’ メモリの読み込み

コマンド d でプログラムの書き込みが行われますが、書き込み先は EEPROM と Flash の2つが選択肢として用意されていることがわかります。EEPROMへの書き込みは eeprom_write_byte() が使われていますが、Flashへの書き込みは、その部分だけアセンブラで書かれています。

余談

「ブートローダ」と言われると、普通のPCにおける起動と同時に大容量記憶装置 (HDD/SSD) からOSのプログラムをRAMに展開するプログラムを連想するかもしれません。1つ気をつけたいのは

  • 普通のPCのブートローダは起動時に毎回OSをHDD/SSDからRAMに展開する
  • マイコンのブートローダはプログラムをROMに書き込む時だけシリアルからの情報をROMに展開する

という違いがあることです。通常動作時のマイコンでは、ブートローダは一応動きますが、特にプログラムをロードするわけでもなくそのまま終了します。

(もしかすると、プログラムをROMに書き込むことそのものがロードであり、マイコンはROMが不揮発性なので電源が落とされてもプログラムがROMにロードされたままの状態を維持する、と考えるのが正しいのかもしれません)

まとめ

  • ユーザプログラムはROMに書き込まれる
  • ROMへの書き込み方法はデバッグユニットを使う方法と、ブートローダを使う方法がある
  • デバッグユニットはJTAG/SWDのインターフェイスがあり、PCとつなぐ時はUSBへの変換のためにデバッガが必要
  • ブートローダを使えばシリアル通信で書き込みができるが、ユーザプログラムとのROM上での共存に注意が必要

参考文献

「マイコン基礎の基礎」シリーズ | Texas Instruments

Serial Wire Debug and the CoreSight Debug and Trace Architecture | Eddie Ashfield et al.

Programming Internal Flash Over the Serial Wire Debug Interface | Silicon Labs

一人1台!全Cortex ARMマイコン対応デバッガのしくみ | トランジスタ技術2014年3月号

Arduinoのブートローダって何?(2) | 京都しなぷすのハード製作記

The Official Arduino AVR core

ARM CoreSight Guilding Optimized ARM SoCs

Update Firmware in the Field Using a Microcontroller’s DFU Mode

Bootloader for dsPIC30F/33F and PIC24F/24H Devices

Be First to Comment

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です