Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

Pololu Forum

ADC and DMA without CPU intervention


#1

Hello,

Has anyone used the ability of CC2511 to do ADC and then DMA the data into XDATA buffer without CPU intervention?

I have setup the Wixel to do that but read negative values (0xFF0) all the time. Not sure what the fix should be. I have posted this question in TI forum but have not heard anything so far. So instead of loosing time, I felt I will post it here as well. Would appreciate your help.

What is not clear is the use of TRIG (ADC DMA trigger and DC6 of dmaConfig). 12.10.2.9 ADC DMA Triggers says that DMA ADC trigger is generated when a sample is ready (as per Table 51). The way I read this is, if the sample is ready, I need to do something about that sample and not expect the ADC data to be moved without CPU intervention into XDATA space i.e., it will not be DMAed into the destination address as specified by dmaConfig. I am using ADC sequence and fixed number of DMA transfers for P0_0, P0_1 and P0_2. The fixed number of transfers to XDATA space is done using repeated single mode of ADC. All these suggest that when ADC sample is ready it will be DMAed directly into XDATA space. I have specified a fixed length transfer and enabled IRQMASK so I do get an interrupt after a fixed number of Transfers into XDATA buffer. But when I read the ADC data from the XDATA buffer, it is all invalid (4095 decimal).

What I have found is at the end of n number of DMA transfers, when I get the DMA interrupt and as per data sheet, which says sample is ready, then if I read the ADC, I get 1.7 mV, which is acceptable (This is done in DMA ISR as shown in the code below). However, for all the other n-1 ADC conversions followed by DMA transfers, the value was 4095 decimal.

TRIG has to be set to either ADC_CHALL or specific channels AIN0, AIN1, AIN2.
I get DMA interrupt only after transfer of n number of fixed byte transfers. My dilemma is even though there are other ways of reading ADC, whether it is through calling adcRead() or through setting up single mode and reading ADC in an interrupt and then moving the data to XDATA space, I want to utilize the powerful feature provided by the hardware so I save on the power as well. But that does not seem to work.

Thanks for your help.

Here is my DMA and ADC configuration.

void configureDma()
{

    sizeL = lowByte(MAX_BUF_SZ);
    sizeH = highByte(MAX_BUF_SZ);


    // Initialize the three axis buffers and be done.
    // X AXIS

    dmaConfig._2.SRCADDRH = XDATA_SFR_ADDRESS(ADCH);
    dmaConfig._2.SRCADDRL = XDATA_SFR_ADDRESS(ADCL);
    dmaConfig._2.DESTADDRH = ((uint16)&adcOutputX[0] >> 8);
    dmaConfig._2.DESTADDRL = (uint16)&adcOutputX[0] ;
    dmaConfig._2.LENL = sizeL;
    dmaConfig._2.VLEN_LENH = sizeH;
    dmaConfig._2.DC6 = 0b10010101;	// Bit 4:0 Trigger on 21,
    					// Bit 7 -- Word
					// Bit 6:5 - 00 Single, 10 Repeat Single
					// Bit 4:0 - DMA Trig 21 10101
    dmaConfig._2.DC7 = 0b00011010;	// IRQ (bit 3) is enabled
    					// Offset 7 Bit 5:4 01 destinc(1 word)
					// priority bits 1:0 
					// Bit 2 not used 
    // Y AXIS
    dmaConfig._3.SRCADDRH = XDATA_SFR_ADDRESS(ADCH);
    dmaConfig._3.SRCADDRL = XDATA_SFR_ADDRESS(ADCL);
    dmaConfig._3.DESTADDRH = ((uint16)&adcOutputY[0] >> 8);
    dmaConfig._3.DESTADDRL = (uint16)&adcOutputY[0];
    dmaConfig._3.LENL = sizeL;
    dmaConfig._3.VLEN_LENH = sizeH;
    dmaConfig._3.DC6 = 0b10010110;	// Bit 4:0 Trigger on 22
    					// Bit 7 -- Word
					// Bit 6:5 - 00 Single, 10 Repeat Single
					// Bit 4:0 - DMA Trig 22 10110
    dmaConfig._3.DC7 = 0b00011010;	// IRQ (bit 3) is enabled
    					// Offset 7 Bit 5:4 01 destinc(1 word)
					// priority bits 1:0 
					// Bit 2 not used 
    
    // Z AXIS
    dmaConfig._4.SRCADDRH = XDATA_SFR_ADDRESS(ADCH);
    dmaConfig._4.SRCADDRL = XDATA_SFR_ADDRESS(ADCL);
    dmaConfig._4.DESTADDRH = ((uint16)&adcOutputZ[0] >> 8);
    dmaConfig._4.DESTADDRL = (uint16)&adcOutputZ[0];
    dmaConfig._4.LENL = sizeL;
    dmaConfig._4.VLEN_LENH = sizeH;
    dmaConfig._4.DC6 = 0b10010111;	// Bit 4:0 Trigger on 23
    					// Bit 7 -- Word
					// Bit 6:5 - 00 Single, 10 Repeat Single
					// Bit 4:0 - DMA Trig 23 10111
    					// Can be changed to PREV Channel
    dmaConfig._4.DC7 = 0b00011010;	// IRQ (bit 3) is enabled
}
void initAdc(void) 
{
  ADCCFG = 0x07;        // Enable ADC input AIN0(P0_0), AIN1(P0_1), AIN2(P0_2)
  ADCCON2 = 0xB2;       // Set reference voltage (AVDD pin), 
  			// decimation rate to 512 (12 bit resolution) and 
			// Sequence is AIN0 to AIN2 
  ADCCON1 = 0x33;       // Set ADC start condition to '11' (ADCCON1.ST = 1)
  ADCCON3 = 0x00;       // Disable extra conversion
}

ISR(DMA,0)
{
    EA =0;

    // DMAIRQ flag provides an interrupt when the transfer count is reached
    // There are 5 DMA Channels.
    // We use four. Ch2, Ch3, Ch4 for 3 I/O ports 
    // and Channel 1 for RX and TX radio packets

    if (IRCON & 0x01)
    {
	irconFlagCount++;
    	IRCON = (IRCON & ~0x01); 		// Clear CPU bit 0
    }

    if (DMAIRQ & 0x04)
    {
	lastAdcReadX[dmaIntCountX] = ADC >> 4;

        dmaIntCountX++;
	setDmaDestAddressX();
	DMAIRQ = DMAIRQ & ~0x04;	// X Axis 
        DMAARM = DMAARM | DMA_CHANNEL_2;  
    }
    if (DMAIRQ & 0x08)
    {
	lastAdcReadY[dmaIntCountY] = ADC >> 4;
        dmaIntCountY++;
	setDmaDestAddressY();
	DMAIRQ = DMAIRQ & ~0x08;	// Y Axis
        DMAARM = (DMAARM | DMA_CHANNEL_3);  
    }
    if (DMAIRQ & 0x10)
    {
	lastAdcReadZ[dmaIntCountZ] = ADC >> 4;
        dmaIntCountZ++;
	setDmaDestAddressZ();
	DMAIRQ = DMAIRQ & ~0x10;	// Z Axis 
        DMAARM = (DMAARM | DMA_CHANNEL_4);  
    }

    DMAIE = 1;		// Enable DMA Interrupt Mask. Same as IEN1 bit 0
    EA = 1;             // enable all interrupts  
}

#2

Hello,

Changing the following lines did the trick:

dmaConfig._2.SRCADDRH = XDATA_SFR_ADDRESS(ADCH);
dmaConfig._2.SRCADDRL = XDATA_SFR_ADDRESS(ADCL);

to

dmaConfig._2.SRCADDRH = XDATA_SFR_ADDRESS(ADC) >> 8;
dmaConfig._2.SRCADDRL = XDATA_SFR_ADDRESS(ADC);

Made the same changes to channel 3 and 4.

Never suspected this and looked everywhere for quite sometime.

Regards


xdata_sfr_address
#3

Hello.

I am not aware of anyone else who has used the DMA and ADC together on the Wixel. It sounds like you were able to solve your problem. Thanks for sharing your code!

–David