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.
