実験 (8): DMA アプリケーション: DMA メモリ対メモリ モード/ペリフェラル モードの実験設計

1. 実験の目的と課題

目的:

1. DMA の使い方を学びます。

2. KEIL5 のシミュレーションとデバッグをマスターします。

タスク:

1. 要件に従ってプログラムを作成し、原則的なメモを作成します。

2. プログラムの動作結果を確認し、それが正しいかどうかを分析します。

3. 構築されたプロジェクトの検証と試運転を完了します。

2. 実験要件

メモリ間モードでは、2 つのメモリ間で高速にデータをコピーできます。まず静的なソース データを定義して内部 FLASH に保存し、次に DMA 転送を使用してソース データをターゲット アドレス (内部 SRAM) にコピーし、最後にソース データとターゲット アドレス データを比較して転送が正確かどうかを確認します。 。

DMA メモリ間の実験では、他のハードウェア要件は必要ありません。プログラムのステータスを示すために RGB カラーのライトのみが使用されます。

3. 実験内容と手順

1. ソフトウェア設計

① 実験的な新しいファイルの手順:

Keil 5 開発環境を実行します。実験コードは比較的単純で、メインのプログラム コードは main.c ファイルにあります。

②プログラミングのポイント:

  • DMA クロックを有効にします。
  • DMA データパラメータを設定します。
  • 転送用に DMA を有効にします。
  • 転送が完了するのを待って、送信元アドレスと宛先アドレスのデータを比較します。

2. 実験手順

(1) Keil uVision5 開発環境を実行し、プロジェクトを作成します。

(2) main.c ファイルをプロジェクトに追加します LED ライトと OLED ディスプレイが必要なので、前の実験で作成した LED ファイルと OLED ファイルをこのプロジェクトに移植し、次のように main.c で呼び出します。図1。

図1 移行手順

 

(3) プロジェクトに DMA 変換関連ファイルを追加します。そのため、図 2 に示すように、MyDMA.c ファイルを作成し、DMA 構成を初期化し、ファイル内に関数 function MyDMA_Transfer() を記述してデータ変換を実行する必要があります。 。

図 2 AD.c コードの書き込み

(4) 図 3 に示すように、将来のプロジェクト ファイルの移植を容易にする MyDMA.h プログラムを作成し、プロジェクト エンジニアリング ツールを移植できるようにします。

図3 AD.hプログラム

(5) main.c プログラムを作成し、MyDMA_Transfe() 関数を呼び出して DMA データを転送します。転送待機中は LED0 が点灯し、転送が成功すると LED1 が点灯します。同時に OLED ディスプレイが表示されます。図 4 に示すように、転送データを示します。

図4 main.cプログラム

エラーや警告なしで正常に実行およびデバッグできます。

3. デバッグの検証と結果

(1) 開発ボードをコンピュータに接続し、STLINK を使用してプログラムを STM32 に書き込みます。

(2) DMA転送が待機状態にあるときは、図 5 に示すように、LED ライトと OLED データを観察します。

図5 DMA転送待機中

(3) DMA転送が転送完了状態になったら、図 6 に示すように LED ライトと OLED データを観察します。

図6 DMA転送が完了した状態

4. 実験的なコード分析

(1) DMA 初期化プログラム:

uint16_t MyDMA_Size;

void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size){
	
	MyDMA_Size = Size;
	
	//开启时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	//初始化
	DMA_InitTypeDef DMA_InitStructure;
	//外设
	DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;//起始地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//是否自增
	//存储器
	DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;//起始地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//数据宽度
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//是否自增
	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向
	DMA_InitStructure.DMA_BufferSize = Size;//缓存区大小,赋值给传输计数器
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输模式,是否自动重装
	DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;//选择硬件触发还是软件触发
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级
	
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1, DISABLE);
	
}

(2) DMA 機能関数プログラム:

void MyDMA_Transfer(void)
{
	DMA_Cmd(DMA1_Channel1, DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);
	DMA_Cmd(DMA1_Channel1, ENABLE);
	//等待转运完成
	while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
	//清理标志位
	DMA_ClearFlag(DMA1_FLAG_TC1);
}	

(3) メイン関数プログラム:

#include "stm32f10x.h"                  // Device header
#include "Delay.h" 
#include "OLED.h" 
#include "MyDMA.h"
#include "LED.h"

uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};
uint8_t DataB[] = {0, 0, 0, 0};

int main(){
	OLED_Init();
	LCD_Init();
	MyDMA_Init((uint32_t)DataA, (uint32_t)DataB, 4);//MDA初始化
	
	OLED_ShowString(1, 1, "DataA");
	OLED_ShowString(3, 1, "DataB");
	OLED_ShowHexNum(1, 8, (uint32_t)DataA, 8);
	OLED_ShowHexNum(3, 8, (uint32_t)DataB, 8);
	
	while(1){
		LED0_on();
		LED1_off();
		//显示转换前数据
		OLED_ShowHexNum(2, 1, DataA[0], 2);
		OLED_ShowHexNum(2, 4, DataA[1], 2);
		OLED_ShowHexNum(2, 7, DataA[2], 2);
		OLED_ShowHexNum(2, 10, DataA[3], 2);
		OLED_ShowHexNum(4, 1, DataB[0], 2);
		OLED_ShowHexNum(4, 4, DataB[1], 2);
		OLED_ShowHexNum(4, 7, DataB[2], 2);
		OLED_ShowHexNum(4, 10, DataB[3], 2);
		
		Delay_ms(1000);
		
		MyDMA_Transfer();//DMA数据转运
		LED1_on();
		LED0_off();
		//显示转换后数据
		OLED_ShowHexNum(2, 1, DataA[0], 2);
		OLED_ShowHexNum(2, 4, DataA[1], 2);
		OLED_ShowHexNum(2, 7, DataA[2], 2);
		OLED_ShowHexNum(2, 10, DataA[3], 2);
		OLED_ShowHexNum(4, 1, DataB[0], 2);
		OLED_ShowHexNum(4, 4, DataB[1], 2);
		OLED_ShowHexNum(4, 7, DataB[2], 2);
		OLED_ShowHexNum(4, 10, DataB[3], 2);

		Delay_ms(1000);
		
		DataA[0] ++;
		DataA[1] ++;
		DataA[2] ++;
		DataA[3] ++;
	}
}

5. 実験の概要

この実験は主に DMA メモリ間動作の実験です。KEIL5 をシミュレーションとデバッグに使用することで、DMA の使用方法を学び、DMA の構成と制御をマスターし、KEIL5 でプログラムをシミュレーションおよびデバッグする方法も学びました。以下に本実験の実験概要を示す。

プログラミングでは、まずソース データのメモリ アドレスと宛先アドレスを定義し、次に転送用に DMA コントローラを設定する必要があります。具体的な手順は次のとおりです。

  • ソースデータのメモリアドレスと宛先アドレスを定義します。プログラムでは、まずソース データのメモリ アドレスと宛先アドレスを定義する必要があります。今回の実験ではソースデータは内部FLASHに格納されているため、ソースアドレスとして内部FLASHへのポインタを定義する必要があります。ターゲット アドレスは内部 SRAM であるため、内部 SRAM へのポインタをターゲット アドレスとして定義する必要があります。
  • DMA コントローラを設定します。DMA コントローラの構成には、DMA 転送モード、転送データの種類、転送データ長、転送元アドレスと転送先アドレスなどが含まれます。この実験ではメモリ間モードを選択するため、転送モードをメモリ間モードに設定する必要があります。転送元データ、転送先アドレスともに 16 ビットのため、転送データタイプはハーフワードとなります。送信データ長は、静的なデータ長、すなわち送信するデータの長さである。ソース アドレスは内部 FLASH のアドレス、デスティネーション アドレスは内部 SRAM のアドレスです。DMA コントローラを設定した後、DMA コントローラを有効にする必要があります。
  • プログラムを実行して結果を確認します。プログラムを作成した後、コードをコンパイルしてダウンロードする必要があります。ダウンロードが完了したら、KEIL5 でシミュレートしてデバッグする必要があります。シミュレーション中に、CPUのレジスタ値やメモリ値を観察することで、プログラムが正しく実行されているかどうかを確認できます。デバッグ プロセス中に、シングル ステップ実行やブレークポイント デバッグなどの機能を使用してプログラムをデバッグできます。プログラムの実行後、送信元データと宛先アドレス データを比較して、送信が正確かどうかを確認する必要があります。

この実験では、DMA メモリ間操作を実装し、内部 FLASH から内部 SRAM にソース データを転送することに成功しました。送信元データと宛先アドレスデータを比較すると、送信結果が正確であることがわかります。デバッグプロセス中に、DMA 転送完了後に DMA コントローラが時間内にオフにならず、プログラムが異常になるため、プログラムが不安定に動作する場合があることがわかりました。この問題は、DMA コントローラをオフにするコードを追加することで解決できます。

この実験により、DMA のメモリ間の操作についての理解が深まり、KEIL5 でプログラムをシミュレートおよびデバッグする方法を学びました。同時に、プログラムの動作が不安定になるなど、よくある問題への対処法も学びました。実験を通じて、初心者にとってプログラムの作成とデバッグは簡単な作業ではないことがわかりました。プログラムを安定して実行し、望ましい効果を達成するには、コードのデバッグと最適化には忍耐が必要です。

実験ではDMA転送のエラーやプログラムの動作が不安定になるなどの問題も発生しました。これらの問題は主に、DMA コントローラを深く理解していないことが原因で、誤った設定が行われてしまいます。情報を調べたり、先生にアドバイスを求めたりすることで、徐々に問題が解決し、DMA コントローラーについての理解が深まりました。

つまり、この実験により、DMA のメモリ間操作の使い方を習得し、KEIL5 でプログラムをシミュレートおよびデバッグする方法を学ぶことができました。同時に、プログラムの作成とデバッグは簡単な作業ではなく、習得するには継続的な学習と練習が必要であることも認識しました。この実験の経験を通じて、今後の研究と仕事において、DMA コントローラの理解と応用にさらに注意を払い、同様の問題にうまく対処できるようにしたいと思います。

ソースコード:実験8

おすすめ

転載: blog.csdn.net/qq_61228493/article/details/131211358