1
\$\begingroup\$

I'm trying to use the DTC to continuously update a variable without CPU intervention. However I am not getting any results and cannot figure out why. Any help would be appreciated.

Here is the method to initialize the DTC:

void initializeDTC(unsigned int channel,unsigned int *pointer){
    // Disable ADC before configuration.
    ADC10CTL0 &= ~ENC;

    // Turn ADC on in single line before configuration.
    ADC10CTL0 = ADC10ON;

    // Set channel, Use SMCLK, 1/8 Divider, Repeat single channel.
    ADC10CTL1 = channel | ADC10SSEL_3 | ADC10DIV_7 | CONSEQ_2;
    // 0 clock ticks, Use Reference, Reference on, ADC On, Multi-Sample Conversion, Interrupts enabled.
    ADC10CTL0 |= ADC10SHT_1 | SREF_1 | REFON | MSC;

    // Put results at specified place in memory.
    ADC10SA = (int)pointer;
    // Only one conversion at a time.
    ADC10DTC1 = 0x01;
    // Repeat conversion.
    ADC10DTC0 = ADC10CT;

    // Start conversion.
    ADC10CTL0 |= ENC | ADC10SC;
    // I've read that trying to start the conversion twice is necessary.
    ADC10CTL0 |= ENC | ADC10SC;
}

I call it like this:

unsigned int temperature;
initializeDTC(INCH_10,&temperature);
// Do stuff with temperature in a loop.

If I've understood the documentation correctly, after each conversion the ADC should start the next conversion because of the MSC bit. At the same time the DTC should transfer the value of ADC10MEM to the value in address in ADC10SA (the value of my pointer). The value of my temperature variable remains at the default value of whatever was in the memory previously (35 thousand and something for me).

I considered the possibility of the DTC having not finished before the next conversion, but the documentation states that the DTC will take at most 4 MCLK cycles. In my application I SMCLK=MCLK and since the conversion takes 8 SMCLK cycles I should be fine in this respect.

\$\endgroup\$
0
\$\begingroup\$

You probably want:

volatile unsigned int temperature;

The compiler might put the variable into a register otherwise, and will not read the updated memory location.

\$\endgroup\$
  • \$\begingroup\$ Well I can tell via debugging that it is not in a register (it's actually memory address 0x05DF), but I went ahead and tried the volatile keyword just in case. There was no difference. \$\endgroup\$ – Fr33dan May 6 '13 at 16:03
0
\$\begingroup\$

I found the answer. The key was when configuring the DTC to set ADC10SA last. If you look at Figure 22-10 of the Users Guide you can see that setting ADC10DTC1 moves the DTC from "Reset" to "Init" state so I would set ADC10DTC0 before that. Then it waits for a write to ADC10SA before starting.

I also made some modifications to allow for easy switching between Sequence and Single channel modes. My final code looks like this:

void initializeDTC(unsigned int channel,unsigned int pointer[], bool sequence){

    // Disable ADC before configuration.
    ADC10CTL0 &= ~ENC;

    // Turn ADC on in single line before configuration.
    ADC10CTL0 = ADC10ON;

    // Make sure the ADC is not running per 22.2.7
    while(ADC10CTL1 & ADC10BUSY);

    // Repeat conversion.
    ADC10DTC0 = ADC10CT;
    // Only one conversion at a time.
    ADC10DTC1 = sequence ? channel >> 12 : 1;
    // Put results at specified place in memory.
    ADC10SA = ((unsigned int)pointer);

    // 8 clock ticks, Use Reference, Reference on, ADC On, Multi-Sample Conversion, Interrupts enabled.
    ADC10CTL0 |= ADC10SHT_1 | SREF_1 | REFON  | ADC10IE | MSC;
    // Set channel, Use SMCLK, 1/8 Divider, Repeat single channel.
    ADC10CTL1 = channel | ADC10SSEL_3 | ADC10DIV_7 | (sequence ? CONSEQ_3 : CONSEQ_2);

    // Enable conversion.
    ADC10CTL0 |= ENC;
    // Start conversion
    ADC10CTL0 |= ADC10SC;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.