DMA的思考でArduinoを制御 - アセンブラ的ポートリードライトのテスト

## イントロダクション

現代の技術革新が進む中、従来のシステムやアプローチでは対応しきれない新しい課題が浮上しています。特に、大規模な制御システムにおいて、コスト効率と性能のバランスを取ることは極めて重要です。高性能なマイクロコントローラを用いて複雑なプログラムを構築する手法もありますが、それではシステムのコストが増大し、開発プロセスも複雑化してしまいます。

こうした背景から、破壊的イノベーションを起こし、安価で高性能なシステムを構築する新たなアプローチが求められています。特に、大型システムでは、車載制御のように複数の安価なマイコンを協調させて制御する分散システムが効果的です。このアプローチにより、個別のマイコンが特定のタスクに最適化され、全体として一貫した動作を実現することが可能です。

さらに、システム全体の効率を最大化するためには、IO仕様書の作成が欠かせません。IO仕様書を詳細に設計することで、DMA（Direct Memory Access）を活用した制御が可能となり、処理がシンプルで、かつ高速化が図れます。DMAによる直接メモリアクセスは、CPUの介入を最小限に抑え、データ転送や制御のパフォーマンスを劇的に向上させるため、システム全体の処理速度を大幅に向上させることができます。

このような背景と動機から、複数のマイコンを利用した分散制御システムの設計と、DMAを活用した効率的なIO処理の可能性について探求することが、本研究の中心テーマとなります。

## 問題定義と目的

### 問題定義

現代の制御システムにおいて、安価で高性能なソリューションを実現することが最優先事項となっています。しかし、高性能を追求するために複雑な設計を採用すると、システムのメンテナンス性が低下し、特に初心者や新たな開発者がプロジェクトに参加した際に理解が難しくなるという課題があります。DMA（Direct Memory Access）による高速データ処理は理想的ですが、その実装は複雑で、コストや開発期間が増大するリスクがあります。一方、シリアル通信を用いた従来のデータ転送手法は、コスト面で優れているものの、速度に限界があり、大規模システムではパフォーマンスのボトルネックとなりがちです。

### 目的

本研究の目的は、システムのコストを抑えつつ高性能を実現するために、複雑なDMAの実装を避けながらも、シリアル通信より高速なデータ処理を達成する新しいアプローチを提案することです。具体的には、SWITCH文を活用して、DMAのような効率的なデータ処理をシンプルな制御手法で実現します。この方法により、システムの処理速度を向上させるとともに、コストを抑えた実装が可能となります。

このアプローチは、コストを最小限に抑えつつ高性能を追求することができ、さらに、メンテナンス性の高いプログラムを提供することで、幅広い開発者層に対応可能なソリューションを提供することを目指しています。


## アプローチと方法論

本研究では、DMA（Direct Memory Access）のような高速データ処理をシンプルに実現するために、ポートのリードライト操作を用いた手法を採用します。ポート操作は直接ハードウェアにアクセスするため、通常の処理よりも高速で効率的です。これにより、シリアル通信を使用する場合と比較して、データの転送速度を大幅に向上させることができます。

### 1. 高速化のアプローチ

DMAのような直接メモリアクセスを実現するためには、複雑なメモリマッピングやアドレス管理が必要となりますが、これには高度なプログラミング技術と設計が求められ、初心者にはハードルが高くなります。そこで、本研究では、ポートのリードライト操作を利用することで、プログラムをシンプルに保ちながらも高速な処理を実現します。この方法は、メモリやデータバスを直接操作することで、通常のI/O操作に比べて高速なデータ転送が可能になります。

### 2. SWITCH文を用いた簡略化

今回の実装では、テストとしてSWITCH文を使用して、ポートから読み取った値に基づき、それぞれのケースに対して簡単な処理を行います。実際のシステムでは、MAP関数を使用したり、複雑な演算やデータ変換を行う場合が多いですが、今回のアプローチではこれらを簡略化し、DMA的な処理をシンプルな形で模倣します。これにより、ポートの値に応じた分岐処理が効率的に行われ、高速かつシンプルなプログラムが構築できます。

### 3. 実装例

プログラムの実装では、ポートの読み込みと書き込みを直接行い、その結果に応じてSWITCH文で分岐処理を実行します。各ケースにおいて、特定のポート値に対して特定の処理を行い、その結果を別のポートに出力する形でシステム全体を制御します。この手法により、DMA的な高速処理を実現しつつ、プログラムの複雑さを抑えることができます。

## 実験方法

本実験では、Maker UNOを使用して、ポートのリードライト操作によるデータ処理の高速化を検証しました。Maker UNOは、各ピンにLEDが実装されているため、ジャンパー線1本で簡単に動作を確認できる利便性があります。

### 使用機材

- [Maker UNOボード](Qhttps://akizukidenshi.com/catalog/g/g116285/ )
 ![Maker UNO](https://akizukidenshi.com/img/goods/L/116285.jpg)
- ジャンパー線
- テスト用プログラム（SWITCH文を使用）

### 実験手順

1. **ハードウェア設定:** Maker UNOを用意しプログラムを書き込める状態にする
2. **プログラムのロード:** テスト用プログラムをArduinoに書き込み、ポートDからの入力に基づいてポートBに出力する処理を実行。
3. **テスト実行:** 、GNDピンにジャンパー線を接続し、反対側をD2ピンからD7ピンに順に差し込み、各ピンの入力状態を確認。
4. **評価:** : ポートBに出力されるデータが期待通りの結果を出すかを確認。具体的には、以下のようにポートBの各ビットと対応するピンについて処理速度と出力の正確性を評価します。

- PORTB0 (D8ピン): ポートD2ピンの入力がLOWの時にLEDが点灯するか確認。
- PORTB1 (D9ピン): ポートD3ピンの入力がLOWの時にLEDが点灯するか確認。
- PORTB2 (D10ピン): ポートD4ピンの入力がLOWの時にLEDが点灯するか確認。
- PORTB3 (D11ピン): ポートD5ピンの入力がLOWの時にLEDが点灯するか確認。
- PORTB4 (D12ピン): ポートD6ピンの入力がLOWの時にLEDが点灯するか確認。
- PORTB5 (D13ピン): ポートD7ピンの入力がLOWの時にLEDが点灯するか確認。

## プログラム例とその説明

### プログラム例

```cpp
void setup() {
  // ポートDの2～7ピンを入力モードに設定し、プルアップを有効にする
  DDRD &= ~(0b11111100);  // D2～D7ピンを入力に設定
  PORTD |= 0b11111100;    // D2～D7ピンにプルアップを有効にする

  // ポートBを出力モードに設定
  DDRB = 0xFF;  // ポートBの全ピンを出力に設定
}

void loop() {
  // ポートDの値を読み取る
  uint8_t portDValue = PIND & 0b11111100;  // D2～D7ピンの状態を取得

  // ポートDの値に基づき、ポートBに出力する値を決定
  switch (portDValue) {
    case 0b11111000: // D2がLOW
      PORTB = 0x01;  // ポートBの最下位ビットをHIGHに設定
      break;

    case 0b11110100: // D3がLOW
      PORTB = 0x02;  // ポートBの2番目のビットをHIGHに設定
      break;

    case 0b11101100: // D4がLOW
      PORTB = 0x04;  // ポートBの3番目のビットをHIGHに設定
      break;

    case 0b11011100: // D5がLOW
      PORTB = 0x08;  // ポートBの4番目のビットをHIGHに設定
      break;

    case 0b10111100: // D6がLOW
      PORTB = 0x10;  // ポートBの5番目のビットをHIGHに設定
      break;

    case 0b01111100: // D7がLOW
      PORTB = 0x20;  // ポートBの6番目のビットをHIGHに設定
      break;

    default: // その他のケース
      PORTB = 0x00;  // ポートBをLOWに設定
      break;
  }

  // ループごとに少し待機
  delay(100);
}
```

### 各部分の説明
1. ポートリードのやり方:
ポートからデータを読み取るには、PINDレジスタを使用します。これは、ArduinoのデジタルポートD（D2～D7）に接続されたピンの現在の状態を反映するレジスタです。
```
uint8_t portDValue = PIND & 0b11111100;
```
このコードでは、PINDからデータを読み取り、ビットマスク0b11111100を使用して、D2～D7ピンの状態のみを取得しています。

2. プルアップのやり方:
プルアップ抵抗を有効にすることで、入力ピンが接続されていない場合に確実にHIGHになるようにします。これにより、入力ピンが確定した状態を維持できます。

```
PORTD |= 0b11111100;
```
このコードでは、D2～D7ピンに内部プルアップ抵抗を有効にしています。

3. ポートライトのやり方:
ポートBにデータを出力するには、PORTBレジスタを使用します。これは、ArduinoのデジタルポートB（D8～D13）に書き込むためのレジスタです。
```
PORTB = 0x01;  // 例えば、PORTBの最下位ビットをHIGHに設定
```
このコードでは、PORTBの最下位ビットをHIGHに設定しています。これにより、対応するピン（D8ピン）がHIGH出力を持つようになります。


## 結果と考察

### 結果

今回のテストでは、Arduino UNOとMaker UNOを使用して、ポートのリードライト操作による高速なデータ処理を実現するプログラムを実行しました。SWITCH文を用いて、ポートDから読み取った値に基づいてポートBに出力を行う簡略化されたDMA的処理を試みた結果、シリアル通信よりも高速なデータ処理が確認されました。また、Maker UNOを使用したことで、各ピンに実装されたLEDを利用し、プログラムの動作を視覚的に確認できるという利便性も得られました。

以下のYouTube動画で、実際のテスト結果を確認することができます。動画では、プログラムの動作や各ピンのLEDの反応を詳しくご覧いただけます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/NAyIBgyexIc" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>




### 考察

今回のプログラムテストは、Arduino UNOを用いて実施しましたが、最終的な実装では、より多くのポートとメモリを持つArduino MEGAを使用することで、さらに複雑で大規模なシステムに対応できるようにする予定です。MEGAを使用することで、ポート数の制約が緩和され、より複雑なデータ処理や分岐が可能になるため、システム全体の柔軟性と拡張性が向上することが期待されます。

今回のテストにおいて、シンプルなSWITCH文による分岐処理でも、DMAのような高速な動作をある程度再現できることが確認されました。これは、複雑なメモリアクセスを伴わない分、初心者にも理解しやすく、またメンテナンス性にも優れたアプローチであると言えます。さらに、プログラムがシリアル通信よりも高速に動作することが確認されたことから、この手法が安価で高性能なシステム構築に寄与する可能性があることが示されました。

最終的にArduino MEGAでの実装に移行することで、さらに多機能で効率的な制御システムの構築が可能になると考えています。また、今回の結果を踏まえて、より高度なデータ処理やエラー処理機能を追加することも視野に入れ、今後の開発を進めていく予定です。