DMA - ダイレクトメモリアクセス
.
GPDMA (General Purpose Direct Memory Access Controller)
Andy Kirkham 氏のMODDMAライブラリで、DMAコントローラを手軽に使おう。
Import libraryMODDMA
MODDMA GPDMA Controller New features: transfer pins to memory buffer under periodic timer control and send double buffers to DAC
The LPC17xx GPDMA
GPDMA は、メモリ、ペリフェラル、レジスタ間のデータ転送をホストCPUの介在なしで行うことができます。
これにより、データ転送中に、CPUは別の仕事をすることが可能です。
LPC1768には8つまでのDMAが利用可能です。
Getting started
宣言
#include "mbed.h" #include "MODDMA.h" MODDMA dma;
MODDMA_Config
メモリ → メモリ は、転送元と転送先のアドレスを指定し、m2m とする。
MODDMA_Config *config; char src[] = "TEST TEST TEST"; char dst[sizeof(src)]; config = new MODDMA_Config; config->channelNum ( MODDMA::Channel_0 ); config->srcMemAddr ( (uint32_t) &src ); config->dstMemAddr ( (uint32_t) &dst ); config->transferSize ( sizeof(src) ); config->transferType ( MODDMA::m2m ); dma.Setup( config ); dma.Enable ( config );
GPDMA_CONNECTION
メモリ → ペリフェラル は、転送元のアドレス、転送先はあらかじめ定義されているペリフェラル名を指定し、m2p とする。
MODDMA_Config *config = new MODDMA_Config; MODDMA::GPDMA_CONNECTION connection; char src[] = "TEST TEST TEST"; connection = MODDMA::UART0_Tx; config->channelNum ( MODDMA::Channel_0 ); config->srcMemAddr ( (uint32_t) &src ); config->dstMemAddr ( connection ); config->transferSize ( sizeof(src) ); config->transferType ( MODDMA::m2p ); dma.Setup( config ); dma.Enable ( config );
割込み
DMA完了時やエラー時の割込みは、コールバック関数を設定する。
void tc_callback () { MODDMA_Config *config = dma.getConfig(); : // Clear DMA IRQ flags. if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq(); } void err_callback () { MODDMA_Config *config = dma.getConfig(); : // Clear DMA IRQ flags. if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq(); } : connection = MODDMA::UART0_Tx; config = new MODDMA_Config; config->channelNum ( MODDMA::Channel_0 ); config->srcMemAddr ( (uint32_t) &src ); config->dstMemAddr ( connection ); config->transferSize ( sizeof(src) ); config->transferType ( MODDMA::m2p ); config->attach_tc ( tc_callback ); config->attach_err ( err_callback );
MODDMA_LLI
連続転送は Linked List Item (LLI) を切り替えながら、循環してDMA転送するようにする。
Import programMODDMA_LLI_test
GPDMA (Direct Memory Access) and LLI (Link List Item) test see: http://mbed.org/users/okini3939/notebook/dma_jp/
MODDMA_Config *config; MODDMA::GPDMA_CONNECTION connection; MODDMA_LLI *lli0, *lli1; char src0[] = "TEST TEST TEST"; char src1[] = "TEST TEST TEST"; connection = MODDMA::UART0_Tx; lli0 = new MODDMA_LLI; lli1 = new MODDMA_LLI; config = new MODDMA_Config; config->channelNum ( MODDMA::Channel_0 ); config->srcMemAddr ( (uint32_t) &src0 ); config->dstMemAddr ( connection ); config->transferSize ( sizeof(src0) ); config->transferType ( MODDMA::m2p ); config->dmaLLI ( (uint32_t)lli0 ); config->attach_tc ( tc_callback ); config->attach_err ( err_callback ); lli0->SrcAddr = ( (uint32_t)&src0 ); lli0->DstAddr = ( (uint32_t)dma.LUTPerAddr(connection) ); lli0->NextLLI = ( (uint32_t)lli1 ); lli0->Control = ( dma.CxControl_TransferSize(sizeof(src0)) | dma.CxControl_SBSize((uint32_t)dma.LUTPerBurst(connection)) | dma.CxControl_DBSize((uint32_t)dma.LUTPerBurst(connection)) | dma.CxControl_SWidth((uint32_t)dma.LUTPerWid(connection)) | dma.CxControl_DWidth((uint32_t)dma.LUTPerWid(connection)) | dma.CxControl_SI() | dma.CxControl_I() ); lli1->SrcAddr = ( (uint32_t)&src1 ); lli1->DstAddr = lli0->DstAddr; lli1->NextLLI = ( (uint32_t)lli0 ); lli1->Control = lli0->Control; dma.Setup( config ); dma.Enable ( config );
Note
- SPIで使う場合、送信(Tx)と受信(Rx)を対でDMAを設定しないとバッファあふれで動かなくなります。
参考
Please log in to post comments.