FingerBuckley:
Gericom:
I made some code to make using DMA much simpler. I can post it here if you want.
That'd be awesome! I'm totally new to the concept of DMA - would you care to provide a brief explanation on how your DMA library works?
Would be much appreciated!
[/quote]
dma.cpp:
#include <Arduino.h>
#include "dma.h"
void DMA_Init()
{
REG_PMC_PCER1 = 1<<7;
REG_DMAC_WPMR = DMAC_WPMR_WPKEY(0x444D4143);//Disable write protection
REG_DMAC_EN = 1;//Enable
REG_DMAC_GCFG = 0x00000010;
}
void DMA_SetupTransfer(int channel, void* src, int src_length, int src_width, int src_incr, void* dst, int dst_width, int dst_incr, int flow_control)
{
REG_DMAC_EBCIDR |= 0x10101 << channel;//Disable Interupts
((uint32_t)(0x400C403C + 0x28 * channel)) = (uint32_t)src;
((uint32_t)(0x400C4040 + 0x28 * channel)) = (uint32_t)dst;
((uint32_t)(0x400C4044 + 0x28 * channel)) = 0;
((uint32_t)(0x400C4048 + 0x28 * channel)) = ((src_length >> src_width) & 0xFFFF) | (6 << 16) | (0 << 20) | ((src_width & 0x3) << 24) | ((dst_width & 0x3) << 28);
((uint32_t)(0x400C404C + 0x28 * channel)) = (0 << 16) | (0 << 20) | ((flow_control & 0x3) << 21) | ((src_incr & 0x3) << 24) | ((dst_incr & 0x3) << 28);
((uint32_t)(0x400C4050 + 0x28 * channel)) = 0 | (0 << 4) | (1 << 9) | (1 << 13) | (1 << 16) | (0 << 20) | (0 << 21) | (0 << 22) | (0 << 24) | (1 << 28);
}
void DMA_SetupMultiTransfer(int channel, dma_transfer_descriptor_t* desc)
{
REG_DMAC_EBCIDR |= 0x10101 << channel;//Disable Interupts
((uint32_t)(0x400C403C + 0x28 * channel)) = 0;
((uint32_t)(0x400C4040 + 0x28 * channel)) = 0;
((uint32_t)(0x400C4044 + 0x28 * channel)) = (uint32_t)desc;
((uint32_t)(0x400C4048 + 0x28 * channel)) = 0;
((uint32_t)(0x400C404C + 0x28 * channel)) = 0;
((uint32_t)(0x400C4050 + 0x28 * channel)) = 0 | (0 << 4) | (1 << 9) | (1 << 13) | (0 << 16) | (0 << 20) | (0 << 21) | (0 << 22) | (0 << 24) | (1 << 28);
}
void DMA_EnableChannel(int channel)
{
REG_DMAC_CHER |= 1 << channel;
}
void DMA_DisableChannel(int channel)
{
REG_DMAC_CHDR |= 1 << channel;
}
int DMA_IsChannelEnabled(int channel)
{
return (REG_DMAC_CHSR >> channel) & 1;
}
dma.h:
#ifndef DMA_H
#define DMA_H
#include <Arduino.h>
#define DMA_WIDTH_BYTE 0
#define DMA_WIDTH_HALF_WORD 1
#define DMA_WIDTH_WORD 2
#define DMA_FC_MEM2MEM 0
#define DMA_FC_MEM2PER 1
#define DMA_FC_PER2MEM 2
#define DMA_FC_PER2PER 2
#define DMA_INCR_INCREMENTING 0
#define DMA_INCR_DECREMENTING 1
#define DMA_INCR_FIXED 2
typedef struct {
uint32_t ul_source_addr; /< Source buffer address */
uint32_t ul_destination_addr; /< Destination buffer address */
uint32_t ul_ctrlA; /< Control A register settings */
uint32_t ul_ctrlB; /< Control B register settings */
uint32_t ul_descriptor_addr; /**< Next descriptor address */
}
dma_transfer_descriptor_t;
void DMA_Init();
void DMA_SetupTransfer(int channel, void* src, int src_length, int src_width, int src_incr, void* dst, int dst_width, int dst_incr, int flow_control);
void DMA_SetupMultiTransfer(int channel, dma_transfer_descriptor_t* desc);
void DMA_EnableChannel(int channel);
void DMA_DisableChannel(int channel);
int DMA_IsChannelEnabled(int channel);
#endif
This reads 512 samples from D0-D7, and sends them over the serial port (I have not tested, but I think it should work):
#include "dma.h"
byte result[512];
void setup()
{
Serial.begin(9600);
pinMode(25, INPUT);//D0
pinMode(26, INPUT);//D1
pinMode(27, INPUT);//D2
pinMode(28, INPUT);//D3
pinMode(14, INPUT);//D4
pinMode(15, INPUT);//D5
pinMode(29, INPUT);//D6
pinMode(11, INPUT);//D7
DMA_Init();
DMA_SetupTransfer(1, (void*)®_PIOD_PDSR, 512, DMA_WIDTH_BYTE, DMA_INCR_FIXED, &result[0], DMA_WIDTH_BYTE, DMA_INCR_INCREMENTING, DMA_FC_MEM2MEM);
DMA_EnableChannel(1);
while(DMA_IsChannelEnabled(1));
for(int i = 0; i < 512; i++)
{
Serial.println(result[i], HEX);
}
}
> Measureino:
> ...
> I think it's a risk to use i.e. C for input and(!) output or you should be very careful to avoid reading from an output pin or writing to an input pin.
That's no problem. The pins are written using a different register than that is used for reading.