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.

MSP430FR5994: trigger adc12b sample from tb0

Part Number: MSP430FR5994


I need a straight answer from a straight question after spending too many hours banging my head.  My goal is to trigger conversions from timer tb0 running in up mode rolling over at rate in compare register with the adc results going into add memory register 0 and then being transferred to a buffer via dma.  I have successively tested the a/d using software triggered conversions.  Now I have the timer, add and dma setup best as I can figure.  Here is the initialization code:

    // set up for single channel conversion triggered on timer and

    // data sent to FRAM buffer.

    setPortField(ADC12CTL0,1,1,0);      // disable adc

    setPortField(ADC12CTL0,4,4,1);      // turn on adc

    setPortField(ADC12CTL0,15,12,0); // ADC12SHT1x  4 clocks

    setPortField(ADC12CTL0,11,8,0);  // ADC12SHT0x  4 clocks

    setPortField(ADC12CTL1,12,10,2);     // sample/hold trigger source 2 select, TB0, CCR0

    setPortField(ADC12CTL1,9,9,1);      // ADC12SHP pulse mode

    setPortField(ADC12CTL1,4,3,0b11);   // clock source = SMCLK

    setPortField(ADC12CTL1,2,1,0);      // ADC12CONSEQx -> Single  channel, single conversion

    setPortField(ADC12CTL3,4,0,0);      // conversion result to mem 0

    setPortField(ADC12MCTL0,4,0,5);     // select A5 for mem 0 in channel, P1.5 single ended

    // setup timer TB0

    setPortField(TB0CTL,9,8,0B10);      // select SMCLK

    setPortField(TB0CCTL0,8,8,0);       // CAP = 0, compare mode

    const float FREQ = 100e3;             // 200 khz

    const float CLK = 16e6;          // timer clock

    float periodReg = (CLK/FREQ) - 1;

    TB0CCR0 = (periodReg + 0.5);

    setPortField(TB0CTL,2,2,1);     // clear timer

    // config p1.5, the analog input for input with no pullup

    setPortField(P1DIR,5,5,0);      // input

    setPortField(P1REN,5,5,0);      // pull up or pull down disabled

    // setup DMA, by default, word transfers, edge sensitive triggers

    setPortField(DMACTL0,4,0,26);   // dma channel 0, trigger 26 (adc eoc)

    setPortField(DMA0CTL,14,12,0);  // single transfer

    setPortField(DMA0CTL,11,10,3);  // destination address is incremented

    setPortField(DMA0CTL,9,8,0);    // source address is unchanged

    setPortField(DMA0CTL,7,7,0);    // word destination

    setPortField(DMA0CTL,6,6,0);    // word source

    DMA0DA = (__SFR_FARPTR)(unsigned long)bigArray;     // starting destination address

    DMA0SA = (__SFR_FARPTR)(unsigned long)&ADC12MEM0;   // address of current adc result

    DMA0SZ = ARRAY_SIZE;            // block size

    setPortField(DMACTL4,2,0,0b001);

setPortField is function I wrote to write the fourth parameter value into fields specified by parameters 2 to 3 into location specified by the first parameter.  Through extensive testing and debugging I know this function works correctly.

When I run my program I can see the the timer is running in the debugger and that the timer interrupt flag is being set  What I don't understand well is the mechanism coupling the a/d trigger to the timer hitting the compare register setting.  Best I can figure from the appropriate msp30 user and data sheet manuals is that the a/d sample and hold source should be set to source 2, TB0, CCR0, according to the docs.

Here is the code that starts things going and loops waiting for a dam interrupt after filling buffer.

    setPortField(ADC12CTL0,1,1,1);      // enable adc

    setPortField(DMA0CTL,4,4,1);        // enable dma

    setPortField(TB0CTL,5,4,1);         // start adc trigger timer

    // for test

    // wait for dma burst completion

    volatile unsigned int dmaFlags = DMAIV;

    while(dmaFlags == 0)

    {

        dmaFlags = DMAIV;

    }

The loop never exits so I pause debugger to look at register values. I see that there is no indication that the a/d ever triggered.

I'm missing something,  What is it?

  • I'm sure you know exactly what setPortField does, but I don't. It's not at all obvious (to me) what a "field" number is, nor why there are two of them. And the use of magic numbers for field values implies (me) digging through the books trying to guess whether they're right or not.

    There are names for all these fields/values, and the assignment style seen in e.g. the "register level" example programs (e.g. SLAC710A) is actually quite frugal in addition to being transparent.

    Just interpolating, I don't see any reference to:
    1) setting OUTMOD to generate a pulse train to the ADC (you probably want OUTMOD_4 since this is CCR0, but you'll need to halve your period)
    2) setting MC to start the timer (you probably want MC_1 for Up mode)

    Also, if you want to run the ADC from SMCLK, make sure it's less than 5.4MHz (data sheet (SLASE54B) Table 5-24).
  • I forgot to add: Yes, SHS=2 is correct for TB0.0. (Some data sheets have a separate SHS table, which is much more convenient.)
  • Thanks Bruce for the time and the response.

    void setPortField(volatile unsigned int &port, int msbBit, int lsbBit, unsigned int value)
    {

    unsigned int mask = 0;
    for(int i = lsbBit; i <= msbBit; i++)
    {
    mask <<= 1;
    mask += 1;
    }
    mask <<= lsbBit;
    // clear field of port
    port &= ~mask;
    // shift value to match field
    value <<= lsbBit;
    // mask of field
    value &= mask;
    // add field to port
    port |= value;
    }

    msbBit and lsbBit define the extent of the bit field. Value is written to the field. port is reference to the register. The names I use in the call are from the header file. I know that this function which defines the masks and does the logical bit operations is all setup at run-time whereas the macros in the header files do such mostly at pre-compie and compile time. That is great for speed. However I use this function for better understanding as to what is happening and for reliability and debuggability since macros are notorious for unexpected behavior and side effects which are difficult to debug.

    I'll set specify an output function for TB0 CCR0. I've done this when I want the compare result to operate an output port bit but it didn't occur to me that was required for internal coupling to the adc. Not clear to me in docs. Also I have trouble getting to appropriate examples for some reason, I've tried.

    I see the spec on max adc clock in the data sheet, but I thought I saw that it could operate up to 16. I will scale it back, thanks for the tip.

    Will let you know how it works out.

    Fred
  • Fair enough, but the easier you make it for people to help you, the more volunteers you'll get.

    I hope everything worked out.

**Attention** This is a public forum