Function generator using the DAC output, using DMA alone.

Dependents:   DACDMAfuncgenlib

This library has been inspired by MODDMA example4.h.

Some differences compared with the MODDMA example: 1) this DMAFuncGen class can work using dma alone (no ISR required, although there is a callback routine included if you would like to synchronize something to the function generator), and 2) there is only one buffer (not two).

It is intended for the LPC1768. It has been tested and seems to work fine.

For a demo program, see

Import programDACDMAfuncgenlib

Generate a sine wave on the Analog Output using DMA alone.

Committer:
Mischa
Date:
Sun Dec 29 01:00:30 2013 +0000
Revision:
0:337ad0fe7734
First version.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Mischa 0:337ad0fe7734 1 #include "assert.h"
Mischa 0:337ad0fe7734 2 #include "DMAFuncGen.h"
Mischa 0:337ad0fe7734 3
Mischa 0:337ad0fe7734 4 //DigitalOut led1(LED1);
Mischa 0:337ad0fe7734 5
Mischa 0:337ad0fe7734 6 DMAFuncGen::DMAFuncGen(MODDMA& dma, MODDMA::CHANNELS channel) : dma(dma) {
Mischa 0:337ad0fe7734 7 conf.channelNum( channel );
Mischa 0:337ad0fe7734 8 buffer_size = 0;
Mischa 0:337ad0fe7734 9 buffer = NULL;
Mischa 0:337ad0fe7734 10 }
Mischa 0:337ad0fe7734 11
Mischa 0:337ad0fe7734 12 #define DAC_POWER_MODE (0 << 16) // DAC output power mode.
Mischa 0:337ad0fe7734 13
Mischa 0:337ad0fe7734 14 uint16_t DMAFuncGen::operator[](const uint16_t idx) {
Mischa 0:337ad0fe7734 15 assert(buffer!=NULL);
Mischa 0:337ad0fe7734 16 assert(idx<buffer_size);
Mischa 0:337ad0fe7734 17 return buffer[idx] & 0xFFC0;
Mischa 0:337ad0fe7734 18 }
Mischa 0:337ad0fe7734 19
Mischa 0:337ad0fe7734 20 void DMAFuncGen::set(int idx, uint16_t x) {
Mischa 0:337ad0fe7734 21 // V = (x>>6) × ((VrefP - VrefN)/1024) + VrefN; VrefN = 0V; VrefP = 3.3V;
Mischa 0:337ad0fe7734 22 buffer[idx] = DAC_POWER_MODE | (x & 0xFFC0);
Mischa 0:337ad0fe7734 23 }
Mischa 0:337ad0fe7734 24
Mischa 0:337ad0fe7734 25 void DMAFuncGen::Connect() {
Mischa 0:337ad0fe7734 26 // Connect DAC to pin
Mischa 0:337ad0fe7734 27 LPC_PINCON->PINSEL1 &= ~(3UL <<20);
Mischa 0:337ad0fe7734 28 LPC_PINCON->PINSEL1 |= 2UL <<20; //AOUT
Mischa 0:337ad0fe7734 29 LPC_PINCON->PINMODE1 &= ~(3UL <<20);
Mischa 0:337ad0fe7734 30 LPC_PINCON->PINMODE1 |= (2UL <<20); // neither pull-up nor pull-down
Mischa 0:337ad0fe7734 31 LPC_PINCON->PINMODE_OD0 &= ~(1UL <<26); // normal (not open drain) mode
Mischa 0:337ad0fe7734 32 }
Mischa 0:337ad0fe7734 33
Mischa 0:337ad0fe7734 34 void DMAFuncGen::Disconnect() {
Mischa 0:337ad0fe7734 35 LPC_PINCON->PINSEL1 &= ~(3UL <<20);
Mischa 0:337ad0fe7734 36 LPC_PINCON->PINSEL1 |= 1UL <<20; //AD0.3, input
Mischa 0:337ad0fe7734 37 LPC_PINCON->PINMODE1 &= ~(3UL <<20);
Mischa 0:337ad0fe7734 38 LPC_PINCON->PINMODE1 |= (2UL <<20); // neither pull-up nor pull-down
Mischa 0:337ad0fe7734 39 LPC_PINCON->PINMODE_OD0 &= ~(1UL <<26); // normal (not open drain) mode
Mischa 0:337ad0fe7734 40 }
Mischa 0:337ad0fe7734 41
Mischa 0:337ad0fe7734 42 void DMAFuncGen::Setup(void) {
Mischa 0:337ad0fe7734 43 // Prepare the GPDMA system.
Mischa 0:337ad0fe7734 44 lli.srcAddr( (uint32_t) buffer );
Mischa 0:337ad0fe7734 45 lli.dstAddr( (uint32_t) &LPC_DAC->DACR );
Mischa 0:337ad0fe7734 46 lli.nextLLI( (uint32_t) &lli);
Mischa 0:337ad0fe7734 47 lli.control( dma.CxControl_TransferSize(buffer_size)
Mischa 0:337ad0fe7734 48 | dma.CxControl_SBSize((uint32_t)MODDMA::_1)
Mischa 0:337ad0fe7734 49 | dma.CxControl_DBSize((uint32_t)MODDMA::_1)
Mischa 0:337ad0fe7734 50 | dma.CxControl_SWidth((uint32_t)MODDMA::word)
Mischa 0:337ad0fe7734 51 | dma.CxControl_DWidth((uint32_t)MODDMA::word)
Mischa 0:337ad0fe7734 52 | dma.CxControl_SI()
Mischa 0:337ad0fe7734 53 | dma.CxControl_I() );
Mischa 0:337ad0fe7734 54
Mischa 0:337ad0fe7734 55 conf.srcMemAddr ( (uint32_t) buffer )
Mischa 0:337ad0fe7734 56 ->dstMemAddr ( MODDMA::DAC ) // unnecessary?
Mischa 0:337ad0fe7734 57 ->transferSize ( buffer_size )
Mischa 0:337ad0fe7734 58 ->transferType ( MODDMA::m2p )
Mischa 0:337ad0fe7734 59 ->dstConn ( MODDMA::DAC )
Mischa 0:337ad0fe7734 60 ->dmaLLI ( (uint32_t) &lli )
Mischa 0:337ad0fe7734 61 ->attach_tc ( this, &DMAFuncGen::TC_callback )
Mischa 0:337ad0fe7734 62 ->attach_err ( this, &DMAFuncGen::ERR_callback );
Mischa 0:337ad0fe7734 63
Mischa 0:337ad0fe7734 64 // Setup dma.
Mischa 0:337ad0fe7734 65 if (!dma.Setup( &conf )) {
Mischa 0:337ad0fe7734 66 error("Unexpected error during DMA.Setup(conf)");
Mischa 0:337ad0fe7734 67 }
Mischa 0:337ad0fe7734 68 }
Mischa 0:337ad0fe7734 69
Mischa 0:337ad0fe7734 70 float DMAFuncGen::Frequency() {
Mischa 0:337ad0fe7734 71 float f;
Mischa 0:337ad0fe7734 72 f=SystemCoreClock;
Mischa 0:337ad0fe7734 73 const int divisors[4] = {4,1,2,8};
Mischa 0:337ad0fe7734 74 f/=divisors[((LPC_SC->PCLKSEL0) >> 22) & 0x03];
Mischa 0:337ad0fe7734 75 f/=buffer_size;
Mischa 0:337ad0fe7734 76 f/=LPC_DAC->DACCNTVAL;
Mischa 0:337ad0fe7734 77 return f;
Mischa 0:337ad0fe7734 78 }
Mischa 0:337ad0fe7734 79
Mischa 0:337ad0fe7734 80 void DMAFuncGen::SetFrequency(float f) {
Mischa 0:337ad0fe7734 81 // Set the transfer frequency.
Mischa 0:337ad0fe7734 82 float cntval;
Mischa 0:337ad0fe7734 83 cntval = SystemCoreClock/(f*buffer_size);
Mischa 0:337ad0fe7734 84 const int PCLK_DAC[4] = {1,2,0,3};
Mischa 0:337ad0fe7734 85 int i=0;
Mischa 0:337ad0fe7734 86 int divisor=1;
Mischa 0:337ad0fe7734 87 while (((cntval/divisor)>65535) && (i<4)) {divisor*=2; i++; }
Mischa 0:337ad0fe7734 88 if (i==4) { divisor=8; i=3; }
Mischa 0:337ad0fe7734 89 LPC_SC->PCLKSEL0 &= ~(3UL<<22);
Mischa 0:337ad0fe7734 90 LPC_SC->PCLKSEL0 |= ((uint32_t) PCLK_DAC[i])<<22;
Mischa 0:337ad0fe7734 91 LPC_DAC->DACCNTVAL = cntval/divisor;
Mischa 0:337ad0fe7734 92 }
Mischa 0:337ad0fe7734 93
Mischa 0:337ad0fe7734 94 void DMAFuncGen::Start() {
Mischa 0:337ad0fe7734 95 dma.Enable( &conf );
Mischa 0:337ad0fe7734 96
Mischa 0:337ad0fe7734 97 // Enable DMA, and TC interrupt
Mischa 0:337ad0fe7734 98 LPC_DAC->DACCTRL = 3UL<<2; // DMA_ENA set, DMA_CNT set
Mischa 0:337ad0fe7734 99 }
Mischa 0:337ad0fe7734 100
Mischa 0:337ad0fe7734 101 void DMAFuncGen::Stop() {
Mischa 0:337ad0fe7734 102 dma.haltAndWaitChannelComplete( (MODDMA::CHANNELS) conf.channelNum() );
Mischa 0:337ad0fe7734 103 LPC_DAC->DACCTRL = 0UL<<2;
Mischa 0:337ad0fe7734 104 }
Mischa 0:337ad0fe7734 105
Mischa 0:337ad0fe7734 106 // Configuration callback on TC
Mischa 0:337ad0fe7734 107 void DMAFuncGen::TC_callback(void) {
Mischa 0:337ad0fe7734 108
Mischa 0:337ad0fe7734 109 // Just show sending buffer complete.
Mischa 0:337ad0fe7734 110 // led1 = !led1;
Mischa 0:337ad0fe7734 111
Mischa 0:337ad0fe7734 112 // Clear DMA IRQ flags.
Mischa 0:337ad0fe7734 113 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
Mischa 0:337ad0fe7734 114 }
Mischa 0:337ad0fe7734 115
Mischa 0:337ad0fe7734 116 // Configuration callback on Error
Mischa 0:337ad0fe7734 117 void DMAFuncGen::ERR_callback(void) {
Mischa 0:337ad0fe7734 118 error("Unexpected error - DMA error callback.");
Mischa 0:337ad0fe7734 119 }
Mischa 0:337ad0fe7734 120