はじめに

レジスタも触ったことのないニセエセ組込みエンジニアなので、リアル組込みエンジニアになりたくて、edXで組込み開発の学習をしました。

結果は、途中で挫折しました。全15週の10週目くらいで挫折。なので、この記事も中途半端な記事になります。

自分はリアル組み込みエンジニアにはなれませんでしたorz.

内容

0,1のフリップフロップから電子回路、レジスタへと、基礎からしっかり解説される。オームの法則とか、忘れた。電子回路は読んで読まないふりをした。

期待していた?電子回路の知識は十分過ぎるほど出てきた。 ADC,DACあたりはほんとうに挫折。

言語はC言語

言語はもちろん、C言語だ。補足的にアセンブラ言語もでてくる。楽勝楽勝。

実践も重視

知識的な部分だけではなく、開発プロセスや品質の考え方、デバッグ手法など実践的な部分も説明される。

開発プロセスでは、フローチャートやサブルーチンといった、手続き型用語が解説されて、やや時代遅れを感じた。

進め方

講義の流れ

イントロダクションとして、2人のコント?から始まる。動画よりも、文章の方が多め。

動画ではとくにパワーポイントは使わずにホワイトボードで解説されるので、字がきれいでなく読みにくい。

Labについて

講義よりも比重が置かれているのが、Labと呼ばれている実機学習。

毎週課題が出されて、それに取り組むことで講義の内容の理解を深める。

課題の評価はテストコードで自動でチェックされる。シミュレータと実機の両方で評価することが求められる。

評価ボードは、Texas Instrumentsの EK-LM4F120XLというものを買った。ネットで注文して購入する必要がある。ARMの Cortex-Mが載っている。

開発環境としては、Keil uVision for the ARM, MDK-Lite (32KB) Editionを利用する。 ARMの開発をするためのIDE.

Lチカ

感想

自己紹介

まず、なぜ私がニセエセ組込みエンジニアなのかを説明したい。そのために、まずは自分のしていた仕事を書こうと思う。このブログに仕事の話を書くのも初めてな気がする。

今は別のこと(社内ニートとも)をしているけれども、ちょっと前までは、ストレージ装置の組込みソフトエンジニアだった。

開発はそこそこ大規模で、機能モジュールごとに担当チームが別れている。

自分の所属していたチームは、エラー発生時のリカバリが担当。つまり、装置でエラーが発生したときに、可用性を失わないためにあらゆる手段をつかってあれこれする役目。

そのなかでも、自分が担当していた部分は、ハードエラーが発生して装置内の各種ドライバから通知を受けたときに、装置の可用性を失わないためはどうすればいいかを一生懸命考える部分。

  Driver -> Me : Error Message

ハードと接するinterfaceはドライバ層で隠蔽されているため、実は自分はレジスタを触ったことがない!

そもそもレジスタがなんだかわからない。雑誌『Interface』や『トランジスタ技術』が会社の休憩ゾーンにおいてあるが、書いてあることがほぼわからない。

これって、組込みエンジニアとしてどうなの?これが、ニセエセ組込みエンジニアたる所以である。

課題

自分は、組込みエンジニアという肩書きではあるものの、実際はハードウェアを理解していない。

以下の記事にとても共感する。

組み込みギョーカイの常識・非常識(8):組み込みソフトウェアって何

ハードウェアの担当者と一緒の打ち合わせに参加しても、正直ちんぷんかんぷん。

ということで、以下が学習目標。

学習目標

DMA Driver が DMA Portのハードエラーを検出して、そのエラー要因ごとに異常を通知する仕組みを理解すること。

DriverがDMAなのは、仕事で一番お世話になったのが DMA Driverの担当の人だったから。

ここからは、勉強メモ。

Embeded System

組み込みシステム。

特定の機能を実現するために機械や機器に組み込まれるコンピュータシステム。

組み込みシステムの主な構成要素は以下。

  • Embedded Systems
    • MicroCotroller
      • Memory
        • RAM
        • ROM
      • Processor(CPU)
      • I/O Ports
      • DAC
      • Bas
      • Timer
    • External Circuits
    • Physical Device
      • Sensor
      • ADC

以下のような特徴をもつ。

  • A microcontroller hidden inside
  • A dedicated purpose
  • Run in real time
  • Input/output is important
  • High volume, low cost
  • Extremely reliable
  • Low power
  • Small size and weight

MicroController

マイクロコントローラー。いわゆる、マイコン。

Microcontrollers, which are microcomputers incorporating the processor, RAM, ROM and I/O ports into a single package, are often employed in an embedded system because of their low cost, small size, and low power requirements.

I/O Port

Input Port/Output Portの略。 Input Portは 外部の世界(外部の集積回路、sensor, etc) からの情報をコンピュータのなかに入れる。Output Portはその逆。

A port is a physical connection between the computer and its outside world.

device driver

a set of software functions that facilitate the use of an I/O port.

GPIO

GPIOはGeneral Purpose Input/Output(汎用入出力)の略語。

GPIO - Wikipedia

LSIチップや電子機器の備える入出力端子の一種で、設定次第で様々な用途に利用できるもの。

ソフトウェアの指示によって任意の入力あるいは出力に利用することができる。複数の端子がGPIOに割り当てられている場合には、これを一つのグループとして一括して制御することができ「GPIOポート」などと呼ばれる

GPIOとは 【 General Purpose Input/Output 】 - 意味/解説/説明/定義 : IT用語辞典

PinはGPIOの構成要素。たとえば、GPIO PortAは、PA0-PA7の8つのPinからできている。

Pins can be configured for digital I/O, analog input, timer I/O, or serial I/O. For example PA0 can be digital I/O or serial input.

Pinのそれぞれが外部デバイスに接続される。用途は、レジスタの設定によって自由にできる。

  • PA1 … LEDへのOutput用
  • PA2 … Switch からの Input用
  • PA3 … UART の Input用
  • PA4 … UART の Output用

Register

コンピュータのプロセッサなどが内蔵する記憶回路で、制御装置や演算装置や実行ユニットに直結した、操作に要する速度が最速の、比較的少量のものを指す。

一般に、論理回路において、フリップフロップなどにより状態を保持する装置をレジスタと呼ぶ。コンピュータにおいては、プロセッサが内蔵しているそれを指す。プロセッサには、プログラムが読み書きできるレジスタ以外に、プロセッサ自身が動作するためのレジスタがあり、内部レジスタなどと呼ばれる。

レジスタ (コンピュータ) - Wikipedia

Registers are high-speed storage inside the processor.

Registerのプログラムでの扱い

Pinを操作するためのレジスタには、アドレス空間の決められたアドレスが割り振られている。(仕様)

プログラムでは、あらかじめDefineを利用してレジスタのアドレスを宣言するのが王道。 volatileをつけることで、コンパイラが最適化してアドレスを変更するのを防ぐ。

#define PA5   (*((volatile unsigned long *)0x40004080))

これは以下と同値。

data = (*((volatile unsigned long *)0x40004080));
data = 0x40004080;
data = (*0x40004080);

そうすると、以下のようにして Registerの値を Read/Writeできる。

# Register Write
PA5 = 0x20;
# Register Read
data = PA5;

初期設定はこんな感じ。

void PortF_Init(void){ volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x00000020;   // 1) F clock
  delay = SYSCTL_RCGC2_R;         // delay
  GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0
  GPIO_PORTF_CR_R |= 0x1F;        // allow changes to PF4-0
  GPIO_PORTF_AMSEL_R &= 0x00;     // 3) disable analog function
  GPIO_PORTF_PCTL_R &= 0x00000000; // 4) GPIO clear bit PCTL
  GPIO_PORTF_DIR_R &= ~0x11;      // 5.1) PF4,PF0 input,
  GPIO_PORTF_DIR_R |= 0x08;       // 5.2) PF3 output
  GPIO_PORTF_AFSEL_R &= 0x00;     // 6) no alternate function
  GPIO_PORTF_PUR_R |= 0x11;       // enable pullup resistors on PF4,PF0
  GPIO_PORTF_DEN_R |= 0x1F;       // 7) enable digital pins PF4-PF0
}

LチカExample抜粋

// symbolic names instead of addresses
#define GPIO_PORTF_DATA_R    (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R     (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R   (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R     (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R     (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_LOCK_R    (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R      (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_AMSEL_R   (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R    (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R       (*((volatile unsigned long *)0x400FE108))

// 2. Declarations Section
//   Global Variables
unsigned long SW1; // input from PF4
unsigned long SW2; // input from PF0

// Subroutine to initialize port F pins for input and output
// PF4 is input SW1 and PF2 is output Blue LED
void PortF_Init(void){ volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x00000020;   // 1) F clock
  delay = SYSCTL_RCGC2_R;         // delay
  GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0
  GPIO_PORTF_CR_R |= 0x1F;        // allow changes to PF4-0
  GPIO_PORTF_AMSEL_R &= 0x00;     // 3) disable analog function
  GPIO_PORTF_PCTL_R &= 0x00000000; // 4) GPIO clear bit PCTL
  GPIO_PORTF_DIR_R &= ~0x11;      // 5.1) PF4,PF0 input,
  GPIO_PORTF_DIR_R |= 0x08;       // 5.2) PF3 output
  GPIO_PORTF_AFSEL_R &= 0x00;     // 6) no alternate function
  GPIO_PORTF_PUR_R |= 0x11;       // enable pullup resistors on PF4,PF0
  GPIO_PORTF_DEN_R |= 0x1F;       // 7) enable digital pins PF4-PF0
}

void FlashSOS(void){
  //S
  GPIO_PORTF_DATA_R |= 0x08;  delay(1);
  GPIO_PORTF_DATA_R &= ~0x08; delay(1);
  GPIO_PORTF_DATA_R |= 0x08;  delay(1);
  GPIO_PORTF_DATA_R &= ~0x08; delay(1);
  GPIO_PORTF_DATA_R |= 0x08;  delay(1);
  GPIO_PORTF_DATA_R &= ~0x08; delay(1);
  //O
  GPIO_PORTF_DATA_R |= 0x08; delay(4);
  GPIO_PORTF_DATA_R &= ~0x08;delay(4);
  GPIO_PORTF_DATA_R |= 0x08; delay(4);
  GPIO_PORTF_DATA_R &= ~0x08;delay(4);
  GPIO_PORTF_DATA_R |= 0x08; delay(4);
  GPIO_PORTF_DATA_R &= ~0x08;delay(4);
  //S
  GPIO_PORTF_DATA_R |= 0x08; delay(1);
  GPIO_PORTF_DATA_R &= ~0x08;delay(1);
  GPIO_PORTF_DATA_R |= 0x08; delay(1);
  GPIO_PORTF_DATA_R &= ~0x08;delay(1);
  GPIO_PORTF_DATA_R |= 0x08; delay(1);
  GPIO_PORTF_DATA_R &= ~0x08;delay(1);
  delay(10); // Delay for 5 secs in between flashes
}

Memory

ROM

書き込んだデータは消去できないが、電源を切ってもデータが消えない読み出し専用のメモリ.

RAM

データの読み書きは自由に行えるが、電源を切ると内容が消えるメモリ(Random Access Memory)

Interface

ハードウェアとソフトウェアを結ぶもの。ここでいうところは、ハードウェアインタフェース。

interface is defined as the hardware and software that combine to allow the computer to communicate with the external hardware.

I/O Port, 外部電子回路、物理的デバイス、ソフトウェアなどを集めたもの。

An interface is defined as the collection of the I/O port, external electronics, physical devices, and the software, which combine to allow the computer to communicate with the external world.

以下の4つに分類される。

  • Parallel - binary data are available simultaneously on a group of lines
  • Serial - binary data are available one bit at a time on a single line
  • Analog - data are encoded as an electrical voltage, current, or power
  • Time - data are encoded as a period, frequency, pulse width, or phase shift

Parallel Interface

パラレルポートとは、コンピュータシステム内で、ばらばらの周辺機器をケーブルで接続するために使われる物理的なインタフェースの一種。

Syncronization

ハードウェアとソフトウェアの同期処理。

ハードウェアのスピードとソフトウェアのスピードは、ソフトウェアの方が早いため相互でやりとりするためには以下の手段がある。

Blind-Cycle

決められた時間SleepしたあとにI/Oステータスをチェックする.

the software writes data to the output device, triggers (starts) the device, then waits a specified time. We call this method blind, because there is no status information about the I/O device reported to the software.

Busy-Wait

Input deviceのデータが更新されたときにI/Oステータスをチェックする。

状態がBusyならばWait(loop), Readyならば次のステップへ。

Busy Wait is a software loop that checks the I/O status waiting for the done state. For an input device, the software waits until the input device has new data, and then reads it from the input device,

Interrupt

ハードウェアが発生させる特別な通知。

An interrupt uses hardware to cause special software execution. With an input device, the hardware will request an interrupt when input device has new data. The software interrupt service will read from the input device and save in global RAM,

Periodic Polling

クロックタイマの割り込み契機でI/Oのステータスをチェック

DMA

Direct Memory Access あるメモリから別のメモリに直接情報を書き込む

Serial Interface

UART

Universal Asynchronous Receiver/Transmitter (UART). 調歩同期方式によるシリアル通信をするための汎用I/F。

有名なので、最近のほとんどのマイコンに搭載されているらしい。

Thread/Process/Task

Thread

A thread is defined as the path of action of software as it executes.

Process

A process is defined as the action of software as it executes.

スレッドとプロセスの違いは、変数のスコープの違い?

Threads share access to I/O devices, system resources, and global variables, while processes have separate global variables and system resources. Processes do not share I/O devices.

実際は、OSによってバラバラ。

Interrupt

Hardware Interrupt Software Action.

Busy-Waitの制御で待ってられない場合は、Interruptを利用する。

ここからは、一般的な説明ではなくてedXの中だけの定義。

Arm/DisArm

Armとは、ハードウェアが割り込みをあげることを有効化する。

DisArmとは、ハードウェアが割り込みをあげることを無効化する。

Enable/Disable

Enableは一時的に割り込みを有効化する。

Disbleは一時的に割り込みを無効化する。

Disable中に発生したInterupptは Pendingされて、Enable時に通知される。

Interruputの初期化処理

  1. Trigger flag set by hardware
  2. the device is armed by software
  3. the device is enabled for interrupts in the NVIC
  4. the processor is enabled for interrupts (PRIMASK I bit is clear)
  5. the interrupt level must be less than the BASEPRI.

Context Switch

割り込みをハードウェアが検知したときに、 foregroundとbackgroundのスレッドを入れ替える。

現在のプロセスの実行を一時停止して、スタックにレジスタ情報を覚えておく。

割り込みハンドラを実行して、ハンドラの実行が終了したらもとのプロセスを再開する。

  1. Current instruction is finished,
  2. Eight registers are pushed on the stack,
  3. LR is set to 0xFFFFFFF9,
  4. IPSR is set to the interrupt number,
  5. PC is loaded with the interrupt vector

Interrupt Service Routine(ISR)

割り込みサービスルーチン。割り込みハンドラともいう。

割り込みハンドラ - Wikipedia

コンテキストスイッチによって、 foregroundで動作している busy-waitなスレッドとISRがスワップされる。

割り込み受け付けによって起動されるオペレーティングシステムやデバイスドライバのコールバックルーチン。割り込みハンドラは割り込み原因によってそれぞれ存在し、割り込みハンドラがそのタスクを完了するまでにかかる時間も様々である。

NVIC

割り込みハンドラに対応させたい関数は、 startup scriptに事前に登録しておく。

vectorというメモリ領域にシステムにどの関数を実行すればいいかをアドレスとして教える。

interrupt発生時は vectorを参照して、それに対応する割り込みルーチンの関数を呼ぶ。

nested vectored interrupt controller (NVIC) manages interrupts, which are hardware-triggered software functions. Some internal peripherals, like the NVIC communicate directly with the processor via the private peripheral bus (PPB). The tight integration of the processor and interrupt controller provides fast execution of interrupt service routines (ISRs), dramatically reducing the interrupt latency.

Acknowledge

割り込みをISRが認識すること。 ISRが割り込みの認識を行った後、同じデバイスからの割り込みが発生しないよう割り込みマスクをする必要がある。そうしないと、クラッシュする恐れがある。

実装でやってはいけないことは以下。

  • 長時間の処理はしてはいけない。
  • 待ち状態になってはいけない、Delay Loopはつかわないほうがよい。
  • 呼んではいけない関数がある。

割り込みハンドラでは必要最小限の処理のみを行い、別のタスクに通知して、メインの処理はそっちでさせるように実装すべき。

ISRからメイン処理への通知方法

ISRとメイン処理はグローバルなメモリ領域を介して情報を受渡しする。

  • Binary Semaphore

ISRで 決められたflagを立てて、メイン処理でそのフラグを監視する。 flagが1ならば、それのフラグに対応する処理を実施する。

  • MailBox

flagとともにデータも渡すこともある。

flagをStatusといい、flagとdataを合わせたデータ構造をMailという。 (MailBox Pruducer-Consumer Pattern)

  • FIFO queue

ISRでFifoなメモリ領域にデータをPUTし、メイン処理のloop処理でで定期的にFifoなdataをチェックし、順次実行する。