連続記事#4 概要設計から詳細設計を行う

# 背景・目的
自社向けの勉強会でなにかテーマを決めて、ソフトウェア開発の上流工程から下流工程まで説明する連続講座を開催し、自分のスキルアップしたいと考えました。
講座参加者に学びになれば尚良、と考えました。この記事は講座資料を再掲・補足説明する位置づけにしたいと考えています。

現在予定している講座はつぎのとおりです。

 * 要求の理解　
 * 要求を仕様化する
 * 設計(概要設計)
 * 設計(詳細設計) ★いまここ
 * TDD　その1 はじめの一歩
 * TDD　その2 タイトル未定

今回の講座の資料はこちらにアップロードしました。

[組み込みソフトウェア基礎_【連続講座 #4】概要設計から詳細設計する](https://www.docswell.com/s/juraruming/KRPQ15-2022-08-25-165916)

前回は[仕様から概要設計する](https://qiita.com/juraruming/items/d0cb03798850c9d0b5d5)というタイトルで概要設計について書きました。
今回は詳細設計について書きます。詳細設計の**詳細**の定義は後述します。


# テーマについて
テーマは**既存組込み製品(CQ EVカート)のマイコンを変更する**と決めました。
テーマ設定理由、EVカートについての説明は連載記事#2　**要求を仕様化する**の[こちらのリンク](https://qiita.com/juraruming/items/d0cb03798850c9d0b5d5#%E3%83%86%E3%83%BC%E3%83%9E%E3%81%AE%E8%AA%AC%E6%98%8E)を参照ください。 

# 詳細設計のスコープ
設計についての記事を書く時に概要設計・詳細設計のように概要・詳細という言葉を使いました。
この**詳細設計**の定義は人・会社により違うと思います。この記事での詳細設計の意味を定義します。

## 詳細設計の定義
ゴールは実装が開始できる粒度で書いた設計図がある状態とします。

例) 概要設計では日本語で変数名・関数名を書いていたが、英語で書く


# 具体的事例
概要設計で書いたオブジェクト図の赤枠部分について詳細設計します。
これは**モータ現在位置を認識し、適切な通電パターンを算出する機能**です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171866/325adce3-7128-adbd-3e09-adab7a394824.png)

## EVカートの説明
詳細設計の事例を書く前に対象装置(EVカート)のハードウェア、制御タイミングについて簡単に説明します。

### ハードウェアブロック
EVカートのハードウェアブロック図です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171866/efe78498-fb2d-6b09-2b93-413cdb9f561b.png)

より詳しい説明は[こちらのページ](https://www.docswell.com/s/juraruming/K3NG1K-2022-06-15-211831#p6)を参照ください。

マイコン(ブロック図のCPU基板に実装されている)はホールセンサでモータの現在位置を認識します。
モータの現在位置からFETの通電パターンを算出します。適切にFETを通電するとモータが駆動します。
**適切な通電**は[制御タイミング](###制御タイミング)に書きます。

### 制御タイミング
モータするための駆動タイミングチャートが下図です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171866/9dd35f7f-6175-7412-80df-596e24e8026d.png)

Hall *と記載されているのが３つのホールセンサ出力です。
UH・UL、VH・VL、WH・WLと記載されている６つがFETです。
図の上部に書かれているのが通電ステージです。
通電ステージが切り替わる時に3つの**ホールセンサのいずれかの出力レベルが変化している**のが特徴です。マイコンはこの切り替わりを検出しFETを通電します。
FETが塗りつぶしで記載されている部分はPWM制御を行う期間になります。PWM制御のDuty比は[ハードウェアブロック](###ハードウェアブロック)のスロットルの開き具合により決めます。

タイミングチャートを表にすると下図になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171866/f213952b-8b6b-6e7d-a5ce-0b2a826c92e6.png)


### 構成要素の責務
それぞれのデバイス・概念の責務について書きます。

#### ホールセンサの責務
モータの現在位置を0, 1で出力する。

#### 通電パターンの責務
ホールセンサのレベルによりFETにセットする信号パターンを算出する。

#### FETの責務
信号パターンの通電することでモータを駆動できる。
FETはスイッチとイメージいただくと良いと思います。


### 通電パターン設定タイミング
通電パターンをFETに設定しモータを駆動するために２つの要件があります。

#### モータ停止状態から駆動する時
EVカートのドライバーがアクセルを開けたらモータを駆動します。
EVカートが停止状態の時はホールセンサ出力レベルが切り替わりません。
マイコンがホールセンサのレベルを入力ポートで読み、現在の通電パターンを認識する必要があります。入力ポートからホールセンサのレベルを読み取り、通電パターンを算出しFETを適切に通電します。


#### モータ回転によりホールセンサの出力が変化する時
モータ回転中は停止状態からの駆動とは状況が違います。
モータ回転するとホールセンサの↑・↓エッジが切り替わります。
マイコンの両エッジ外部割り込みでホールセンサ出力の変化を検出できます。　ホールセンサ出力変化を検出したら通電パターンを算出しFETを適切に通電します。


## 詳細設計
前置きが長かったですが設計について書いていきます。

### クラス導出
前述した用件を満たすためにつぎのクラスを考えました。

![hall_class.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171866/76e267bf-2712-a034-9c90-8bda6f022606.png)

つぎの３つのクラスを思いつきました。

 * hall_sensor_driver: ホールセンサのデバイスドライバ
 * drive_pattern: ホールセンサ出力レベルから通電ステージを算出する
 * motor_driver: モータのデバイスドライバ。通電ステージからFETを通電しモータを駆動する。

harawareはクラスではなく、ホールセンサ・FETなどのハードウェアを指しています。

細かいことですが図に記載したことを補足します。

**hall_sensor_bitmap:**
Hall W=2bit, Hall V=1bit, Hall U=0bitとして、
Hallセンサの読み込み値を2〜0bit目にマッピングした値。
通電ステージ1であれば0x05(Hall W=1, Hall V=0, Hall U=1)。

**pwm_duty:** 
タイミングチャートのPWM制御を行う期間で設定するPWM Duty(%)。0〜100で指定。
この図には登場しないがアクセルの開き具合によりPWM Dutyを決める。
motor_driverは0〜100(%)のPWM Dutyをマイコン機能の設定値(モータ制御機能のタイマカウントなど)に変換し設定する責務を持つ。
PWM 100%を実現するためのマイコン設定値は400、800だったりマイコン・クロックの仕様により変わってくる。　


### 実現可能性の検証
クラス間のメッセージ(メソッドの呼び出し)を図にして、[通電パターン設定タイミング](###通電パターン設定タイミング)の要件の実現可能性を机上で確認します。


#### モータ停止状態から駆動する時
モータ停止状態からモータを駆動する場合のメッセージの流れを図にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171866/1d5cbe63-d4c9-e5c8-1525-aa578c3c9b09.png)

▪️1.1, 1.2, 1.3 read
hall_sensor_driver自らreadメソッドを呼び出し、ホールセンサのレベルを読み込みます。
ホールセンサのレベルはメンバ変数hall_sensor_bitmapに保存します。

▪️2. update
hall_sensor_driverはdrive_patternのupdateメソッドを呼び出します。
drive_patternのメンバ変数stageはhall_sensor_bitmapの値から算出し更新します。

▪️３. drive
drive_patternはmotor_driverのdriveメソッドを呼び出します。
driveメソッドはdrive_patternのメンバ変数stageから通電するFETを算出します。
通電するFETが算出できたらFETを通電しモータを駆動します。

#### モータ回転によりホールセンサの出力が変化する時
モータ回転によりホールセンサ出力が変化する場合のメッセージの流れを図にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171866/4d34eaa1-7c0d-4d1b-d8a3-e8b3896b606c.png)

▪️1 update
hall sensorがhall_sensor_driverのupdateメソッドを呼び出し、hall_sensor_driverのメンバ変数hall_sensor_bitmapを更新します。
これはどういうことかというとホールセンサが接続されている入力ポートの外部割り込みハンドラからhall_sensor_driverのupdateメソッドを呼び出すことを想定しています。
そのため[モータ停止状態から駆動する時](####モータ停止状態から駆動する時)と矢印の向きを変えています。
その後のメッセージの流れは[モータ停止状態から駆動する時](####モータ停止状態から駆動する時)と同じです。


# 設計時に考えたこと
設計時に意識して考えていたことを書きます。

## 命名
クラス名・メンバ変数・メンバ関数の命名はどうすべきか考えました。
命名でソフトウェアの構造は決まると思うため命名は重要だと思っています。
振り返るとhall_sensor_driverクラスのメンバ変数hall_sensor_bitmapは冗長でsensor_bitmapでよかったかも・・・と思っています。

## 階層構造・抽象化
デバイスドライバの階層(hall_sensor_driver・motor_driver)がハードウェアとやりとりするようにしました。　
デバイスドライバの階層を持たずにdrive_patternがホールセンサ・FETとやりとりする構造も考えられますがその構造にはしませんでした。
drive_patternはハードウェアと関連させないように意識しました。
drive_patternはタイミングチャートの【通電ステージ】という**概念**を扱うようにしました。
デバイスドライバの階層より知識をもった階層としました。

# 次回予定
**概要設計から詳細設計を行う**は如何でしたでしょうか?
なにかお役にたてると嬉しいです。
よければ感想などをコメントくださるとありがたく、猫のように喜びます。

次回の自社向け勉強会は9/22(木)で開催予定です。その頃にまた勉強会の内容を記事化したいと考えています。
勉強会の内容はつぎを考えています。

【連続講座 #5】テスト駆動開発 はじめの一歩

詳細設計でプログラムに実装可能な設計図を作成しました。この後は設計図に則り、実装していきますがテスト駆動開発の手法(テストファースト)で進めていきたいと思います。テスト駆動開発を始めるにあたり、次のことを話したいと考えています。

　・テスト駆動開発とは?
　・環境構築
　・テストを書いてみる

最後まで長文を読んでいただきありがとうございました。次回もよろしくおねがいします。