2 ADC Data Transfers by DMA
The bandwidth for all DMA channels is limited to six instruction cycles. Therefore, if the CPU clock is 200 MHz, all DMA channels cannot transfer data words faster than 200 MHz / 6 = 33.3 MHz (word transfers per second). The transferred word size does not matter, whether it is one byte, two bytes or four bytes. To move ADC data using DMA, the ADC conversion rate should be lower than 33 MSPS. Since all DMA channels share the same bandwidth, only one DMA channel should be used (active) in the application during ADC data transfers. In Capturing ADC Data Using DMA at 33 MSPS Conversion Rate, DMA channel 0 moves 33 MSPS ADC data to a RAM buffer. For robust timing, the CPU/DMA and ADC are clocked from the same PLL. The example code should be executed on the dsPIC33A Curiosity Platform Development Board (EV74H48A) with the dsPIC33AK256MPS306 GP DIM (EV02E57A).
Capturing ADC Data Using DMA at 33 MSPS Conversion Rate
// disable WDT
#pragma config FWDT_WDTEN = SW
#include <xc.h>
#define BUFFER_SIZE 800
unsigned short buffer[BUFFER_SIZE];
int main(){
// initialize clock
OSCCTRLbits.POSCEN = 1; // POSC enable
OSCCFGbits.POSCMD = 0; // EC POSC clock on OSCI pin connected to 8MHz MEMS
PLL1CONbits.ON = 1;
OSCCTRLbits.PLL1EN = 1;
while(OSCCTRLbits.PLL1RDY == 0);
PLL1CONbits.FSCMEN = 0; // disable clock fail monitor
VCO1DIVbits.INTDIV = 2; // VCO divider 1:4 = 200MHz
PLL1DIVbits.PLLFBDIV = 100; // VCO = 800 MHz
PLL1DIVbits.PLLPRE = 1;
PLL1DIVbits.POSTDIV1 = 3; // PLL1 = 800MHz:3 = 266.6 MHz for ADC
PLL1DIVbits.POSTDIV2 = 1;
PLL1CONbits.DIVSWEN = 1;
while(PLL1CONbits.DIVSWEN == 1);
PLL1CONbits.NOSC = 3; // clock from POSC EC (8MHz MEMS on board)
PLL1CONbits.OSWEN = 1;
while(PLL1CONbits.OSWEN == 1);
PLL1CONbits.FOUTSWEN = 1;
while(PLL1CONbits.FOUTSWEN == 1);
PLL1CONbits.PLLSWEN = 1;
while(PLL1CONbits.PLLSWEN == 1);
while(PLL1CONbits.CLKRDY == 0);
// CPU clock 200 MHz (Generator 1)
CLK1CONbits.ON = 1;
CLK1CONbits.NOSC = 7; // PLL1 VCO divider
CLK1CONbits.OSWEN = 1;
while(CLK1CONbits.OSWEN == 1);
while(CLK1CONbits.CLKRDY == 0);
// ADC input clock (Generator 6)
CLK6CONbits.ON = 1;
CLK6CONbits.NOSC = 5; // PLL1 266.66 MHz or 33.3 MSPS
CLK6CONbits.OSWEN = 1;
while(CLK6CONbits.OSWEN == 1);
while(CLK6CONbits.CLKRDY == 0);
// initialize UART
#define UART_BAUD (230400UL) // UART baud rate
#define FCY (200000000UL) // FCY frequencyu in Hz
_RP49R = 10;// map UART1 TX to RP49/RD0 pin (board PKOB UART)
U1BRG = FCY/2/UART_BAUD/4-1;
U1CONbits.BRGS = 1;
U1CONbits.TXEN = 1;
U1CONbits.ON = 1;
// DMA channel 0 moves 33MSPS data from ADC to RAM
DMACONbits.ON = 1;
// DMA accesses entire RAM
DMALOW = 0;
DMAHIGH = -1;
DMA0CHbits.SIZE = 1; // 16-bit
DMA0CHbits.DONEEN = 1; // interrupt enable
DMA0CHbits.TRMODE = 1; // repeated one shot
DMA0CHbits.DAMODE = 1; // increment buffer address
DMA0CHbits.SAMODE = 0; // same ADC data register
DMA0CHbits.RELOADC = 1; // reload counter
DMA0CHbits.RELOADD = 1; // reload destination address
DMA0SELbits.CHSEL = 47; // trigger from ADC 1 channel 0 (option 47)
DMA0CHbits.CHEN = 1;
DMA0SRC = (unsigned long)&AD1CH0RES; // get data from ADC1 channel #0
DMA0DST = (unsigned long)buffer; // store ADC1 results in a buffer
DMA0CNT = BUFFER_SIZE;
AD1CH0CON1bits.PINSEL = 1; // convert AD1AN1/RA4 pin connected to J4 on board
AD1CH0CON1bits.SAMC = 0; // 0.5 TAD
AD1CH0CON1bits.IRQSEL = 0; // DMA trigger each conversion
AD1CH0CON1bits.TRG1SRC = 1; // first trigger from software
AD1CH0CON1bits.TRG2SRC = 2; // repeat conversions back-to-back
AD1CH0CON1bits.MODE = 2; // counter mode
AD1CH0CNT = BUFFER_SIZE; // number of back-to-back conversions
AD1CONbits.ON = 1; // enable ADC
while(AD1CONbits.ADRDY == 0); // wait when it is ready
while(1){
// start conversions
_DMA0IF = 0;
AD1SWTRGbits.CH0TRG = 1;
while(_DMA0IF == 0); // wait when done
// output to UART
unsigned short count = BUFFER_SIZE;
unsigned short* pointer = buffer;
while(count--){
while(U1STATbits.TXBE == 0); // wait for a free space in FIFO
U1TXB = 0x55; // MPLAB Data Visualizer start token
U1TXB = (unsigned char)*pointer; // low byte of UINT16
U1TXB = (unsigned char)(*pointer>>8); // high byte of UINT16
U1TXB = 0xaa;// MPLAB Data Visualizer end token
pointer++;
}
}
return 1;
}
