This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Repeating Single Channel Conversion ADC with DTC

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 | ADC10IE;

    // Put results at specified place in memory.
    ADC10SA = (unsigned 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).

  • Joseph Tignor said:
    after each conversion the ADC should start the next conversion because of the MSC bit

    Yes, except in single-conversion mode, of course.

    Joseph Tignor said:
    At the same time the DTC should transfer the value of ADC10MEM to the value in address in ADC10SA (the value of my pointer)

    Yes. However, you set up the DTC to do only one transfer. The next conversionr esult will be ignored by the DTC and the ADC10ISR is called because of the conversion complete, not because of another DTC transfer being done.

    You can configure the DTC for any number of transfers, independently of the number of transfer the ADC10 will do. The two are independent regarding the logic of how many conversions are done and how many results are transfered.

  • Jens-Michael Gross said:
    Yes, except in single-conversion mode, of course.

    Then is the Figure 22-7 in slau144i incorrect? It says that as long as CONSEQx = 10, MSC = 1 and ENC = 1 it should do a single channel conversion repeatedly.

    Jens-Michael Gross said:
    However, you set up the DTC to do only one transfer.

    Looking at the Figure 22-10 it says that if the ADC10CT = 1 when the number of writes configured is completed it will reset the counter and do write again. Since I only want one spot in memory written to is this not correct?

  • Joseph Tignor said:
    Then is the Figure 22-7 in slau144i incorrect? It says that as long as CONSEQx = 10

    You misundestood. Single channel conversion mode is CONSEQx=00. CONSEQx=10 is repeated single channel conversion mode. And it of course repeats the conversion over and over again.

    Joseph Tignor said:
    if the ADC10CT = 1 when the number of writes configured is completed it will reset the counter and do write again

    You're right, I overlooked this.
    It's possible that you need to set this bit bevore you write the count to ADC10DTC0 (as this will 'arm' the DTC and the later set ADC10CT might be ignored).

    However, why do you use the DTC at all if oyu only want to transfer one result to the saem address= You'll need to check for ADC10IFG (or trigger an ISR) to know that a new value has arrived. You could as well look at ADC10MEM when the conversion is done and ADC10IFG is set. Same result, less effort.

    Unless, of course, if the target address is TXBUF or a port, so the transfer itself triggers something (like sending an 8 bit conversion result, or outputting the result value on the port pins).

  • After your last statement in routine initializeDTC(INCH_10, &temperature) is executed the function returns but the A/D continues to run and tries to fill update the variable &temperature? Is that the intent?

  • Joseph Raslavsky said:

    After your last statement in routine initializeDTC(INCH_10, &temperature) is executed the function returns but the A/D continues to run and tries to fill update the variable &temperature? Is that the intent?

    Yes this is the intent

    Jens-Michael Gross said:
    Single channel conversion mode is CONSEQx=00. CONSEQx=10 is repeated single channel conversion mode.

    Repeated Conversion is what I want. I'm sorry if this wasn't clear.

    Jens-Michael Gross said:
    However, why do you use the DTC at all if oyu only want to transfer one result to the saem address= You'll need to check for ADC10IFG (or trigger an ISR) to know that a new value has arrived. You could as well look at ADC10MEM when the conversion is done and ADC10IFG is set. Same result, less effort.

    We only need to read one input at the moment, but in the future we will be switching to Repeated Sequence of Channels Conversion and I was hoping to have code that could easily be adapted when that time comes. I even tried switching to repeated sequence (using CONSEQ_3, ADC10DTC1 = 10 and an array instead of a pointer) but it did not update either.

    Jens-Michael Gross said:
    It's possible that you need to set this bit bevore you write the count to ADC10DTC0 (as this will 'arm' the DTC and the later set ADC10CT might be ignored).

    I tried setting DTC1 before I set DTC0, then before I set SA. Then I moved the whole DTC setup (DTC0, DTC1 and SA) to before the actual ADC setup (CTL0 and CTL1). None of this had any effect.

  • Joseph Tignor said:
    Repeated Conversion is what I want. I'm sorry if this wasn't clear.

    No apparently I wasn't clear enough when mentioning the single converison mode as exception to the 'after conversion, the next conversion starts due to MSC bit'. It was added because this thread may be later read by someone else who does not use a repeated or sequence mode.

    Joseph Tignor said:
    We only need to read one input at the moment, but in the future we will be switching to Repeated Sequence

    Okay, that's a good reason :)

    Joseph Tignor said:
    None of this had any effect.

    Maybe it is a quirk in the DTC that happens for the (as I already noted) unlikely case of a count of 1. Why don't you try it with 2 for the DTC count? This should write to the given address and the word behind (so reserve 32 bit, e.g. a long, or a union of a long and two ints).
    If this solves the problem, you apparently discovered a bug in the DTC engine.

  • Jens-Michael Gross said:
    Why don't you try it with 2 for the DTC count? This should write to the given address and the word behind (so reserve 32 bit, e.g. a long, or a union of a long and two ints).
    If this solves the problem, you apparently discovered a bug in the DTC engine.

    Damn I thought this might be a possibility because I remember someone else mentioning a problem with getting a unwanted reading from the DTC when using repeated sequence mode. But it does nothing. At this point my code uses an array instead of a pointer. I left it that way after I attempted repeated sequence (I even made sequence mode a parameter option). No position in the array was changed.

    After all the current change I've made in an attempt to make this work I feel I should update this thread. At this point my 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;

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

        // 0 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);

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


    And the calling code again:

        unsigned int temperature[10];
        
        initializeDTC(INCH_10, temperature, false);


    Using either true or false still results in no values in memory being updated. We've got to be missing something obvious.

  • I found the answer. The key is to set ADC10SA last. Looking at Figure 22-10 the setting setting ADC10DTC1 takes the DTC from "Reset" into "Init" state so I would set the configurations on ADC10DTC0 before that. The DTC then waits for ADC10SA to be set before starting. My finally code looks like this (and works perfectly):

    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);

        // 0 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;
    }
  • Joseph Tignor said:
    The key is to set ADC10SA last.

    Oh, yes, you're right. I thought tht setting the count would arm the DTC, but instead it is the target address write. Now that you mention it, I remember reading it (I never used the DTC in one of my own projects). This is different to the USI (where the count write starts the transfer, not the write of the data register) and the DMA (where there is an individual enable bit).

    But it makes sense. If you work with multiple buffers, you only have to write the next address and the count stays the same. So you save some clock cycles.

    Sorry for not remembering this sooner.

**Attention** This is a public forum