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.

MSP430F5659: MSP430F5659 Configure the DAC to work with the DMA.

Part Number: MSP430F5659

I have been trying to get the DAC to trigger an interrupt to the DMA so that there will be as little latency in the data transfer as possible. My current setup is working, but does not produce a desirable result from the output of the DAC as there is a 10us delay between each of the sine waves. The DAC0 output is on CH1, the other channels are irrelevant. I expect that is delay is being created by the way that I am triggering the DMA in software. Any help would be appreciated.

#include <msp430.h> 
#include <math.h>
#include <stdlib.h>

//=====================================================================================================================================================================
//                                                                  Global Variables
//=====================================================================================================================================================================
unsigned char MST_Data_index = 1;
unsigned char MST_Data[2];
/**
 * main.c
 */

void digital_pot_clt(unsigned int ctl, unsigned int val, unsigned char *ctl1, unsigned char *ctl2) {

    unsigned int to_convert;
    unsigned int tmp_val;
    unsigned int tmp_ctl;
    unsigned int pot_cmd;
    //0. Check if the resistance value is greater than 1023.
    if (val > 1023) {
        tmp_val = 511;
    }
    else {
        tmp_val = val;
    }

    //1. Check the control value.
    if (ctl <= 6 & ctl >= 0) {
        tmp_ctl = ctl << 10;
    }
    else
        tmp_ctl = 0;

    //2. Convert the 16 Bit Control Value to Two 8 Bit Values
    pot_cmd = tmp_ctl | tmp_val;

    ctl1[0] = pot_cmd;
    ctl2[0] = pot_cmd >> 8;

}

int main(void)
{
    //0. Setup a sin function in memory.
    unsigned int v[27];
    //40kHz

    v[0] = 2046;
    v[1] = 2554;
    v[2] = 3031;
    v[3] = 3446;
    v[4] = 3772;
    v[5] = 3991;
    v[6] = 4087;
    v[7] = 4056;
    v[8] = 3898;
    v[9] = 3623;
    v[10] = 3250;
    v[11] = 2801;
    v[12] = 2305;
    v[13] = 1792;
    v[14] = 1296;
    v[15] = 846;
    v[16] = 472;
    v[17] = 196;
    v[18] = 37;
    v[19] = 3;
    v[20] = 98;
    v[21] = 315;
    v[22] = 641;
    v[23] = 1055;
    v[24] = 1531;
    v[25] = 2039;
    v[25] = 2046;

    //1. Configure the WDT to stop working.
    WDTCTL = WDTPW | WDTHOLD;

    //2. Configure the DAC to,
    //a. Configure the input range to full scale output.
    DAC12_0CTL0 = DAC12IR;
    //b. Configure the DAC reference voltage to AVCC.
    DAC12_0CTL0 |= DAC12SREF_1;
    //c. Configure the DAC Amplifier Setting -> Input Buffer: HS/HC & Output Buffer: HS/HC
    DAC12_0CTL0 |= DAC12AMP_5;
    //d. Enable Conversion.
    DAC12_0CTL0 |= DAC12ENC;
    //e. Turn on Calibration.
    DAC12_0CTL0 |= DAC12CALON;
    //f. Select the load trigger for the DAC.
    //DAC12_0CTL0 |= DAC12LSEL1;
    //g. Turn on the dac ie. //DAC12IFG will not be set if this is enabled.
    //DAC12_0CTL0 |= DAC12IE;


    //3. Configure the DMA controller
    //a. Source address.
    __data16_write_addr((unsigned short) &DMA0SA, (unsigned long) &v[0]);
    //b. Destination Address
    __data16_write_addr((unsigned short) &DMA0DA, (unsigned short) &DAC12_0DAT);
    //c. Set the block size.
    DMA0SZ = 26;
    //d. Repeated Single Transfer.
    DMA0CTL = DMADT_5;
    //e.  Source address is incremented.
    DMA0CTL |= DMASRCINCR_3;
    //f. Destination address is unchanged.
    DMA0CTL |= DMADSTINCR_0;
    //h. Enable DCA Interrupt
    //DMACTL0 |= DMA0TSEL_25;
    //g. Enable DMA0
    DMA0CTL |= DMAEN;
    //i. Global Interrupt Enable
    __bis_SR_register(GIE);
    //DAC12_0CTL0 = DAC12IFG;


    //4. SPI Configuration
    //a. Configure the pins for SPI output
    //i. Port 8 Pins,
    //PIN1 (UCA1CLK)
    //PIN2 (UCA1SIMO)
    //PIN3 (UCA1SOMI)
    P8SEL = 0b00001110;
    P8DIR = 0b00000000;

    //ii. Port 2 Pins
    //===PIN2 U10 RST===
    //Set the direction.
    P2DIR = 0b00000100;
    //Set the pull up resistor (disable).
    P2REN = 0b00000000;
    //Set the drive strength (full).
    P2DS = 0b00000100;
    //Set the pin function (gpio).
    P2DS = 0b00000000;
    P2OUT = BIT2;
    //===PIN0 U10 SYNC===
    //Set the direction.
    P2DIR |= 0b00000001;
    //Set the pull up resistor (disable).
    P2REN |= 0b00000000;
    //Set the drive strength (full).
    P2DS |= 0b00000001;
    //Set the pin function (gpio).
    P2DS |= 0b00000000;
    P2OUT |= BIT0;
    //===PIN1 U10 RDY===
    //Set the direction.
    P2DIR |= 0b00000000;
    //Set the pull up resistor (enable).
    P2REN |= 0b00000000;
    //Set the drive strength (full).
    P2DS |= 0b00000000;
    //Set the pin function (gpio).
    P2DS |= 0b00000000;

    //iii. Univ. Serial Comm Module (SPI)
    // **Put state machine in reset**
    UCA1CTL1 |= UCSWRST;
    // 3-pin, 8-bit SPI master
    // Clock polarity high, MSB
    UCA1CTL0 |= UCMST|UCSYNC|UCCKPL|UCMSB;
    // SMCLK
    UCA1CTL1 |= UCSSEL_2;
    // /2
    UCA1BR0 = 0x02;
    UCA1BR1 = 0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      ;
    // No modulation
    UCA1MCTL = 0;
    // **Initialize USCI state machine**
    UCA1CTL1 &= ~UCSWRST;
    // Enable USCI_A0 RX,TX interrupt
    //UCA1IE = UCRXIE;
    //iv. Setup the SYNC POT input.
    P2OUT |= 0;

    //v. Wait for slave to initialize
    __delay_cycles(100);

    //vi. Create the POT data.
    digital_pot_clt(4, 1, &MST_Data[0], &MST_Data[1]);

    //vii. Send the POT data.
    while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
     UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character
    MST_Data_index--;
    while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
          UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character

    P2OUT &= BIT2;

    P2OUT |= 0;

   //v. Wait for slave to initialize
   __delay_cycles(100);

   //vi. Create the POT data.
   digital_pot_clt(2, 512, &MST_Data[0], &MST_Data[1]);

   //vii. Send the POT data.
   while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
    UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character
   MST_Data_index--;
   while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
         UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character

       P2OUT &= BIT2;

    for(;;) {
        DMA0CTL |= DMAREQ;
    }

	//return 0;
}

  • I think you want a timer-trigger here, to evenly pace the DAC samples. Data sheet (SLAS700D) Table 6-13 shows that (e.g.) trigger=1 is TA0CCR0.

    So set timer TA0 to run in Up mode (SMCLK is probably good) with CCR0 the number of clocks (roughly microseconds) between samples. Then make it the trigger with something like:
    > DMACTL0 |= DMA0TSEL_1; // Trigger from TA0CCR0 CCIFG per SLAS700D Table 6-13
    You don't need to set the CCIE, the CCIFG will be set anyway.

    Once your DMASZ=26 bytes is finished (either spin for DMAEN=0 or use an ISR) you'll have one sample time (CCR0) to re-start the DMA by setting DMAEN=1.

    [Edit: I mis-read the part number the first time, but the principle is the same. I've changed the data sheet document number and the Table number.]

  • Hi Allan

    Could you add a toggle GPIO in the for loop like this?

       for(;;) {

           toggle GPIO here

           DMA0CTL |= DMAREQ;

       }

    And capture the wave for me?

    By the way what's the waves of #3 and #4 in your  capture? 

    If you want the maxmum DAC fresh frequency you can refer to the user's guide 31.2.8 

    "For devices that contain a DMA, each DAC channel has a DMA trigger associated with it. When DAC12IFG is set, it can trigger a DMA transfer to the DAC12_xDAT register. DAC12IFG is automatically

    reset when the transfer begins. If the DAC12IE is also set, no DMA transfer occurs when the DAC12IFG is set."

    The better way I think you should use a Timer to tirgger the DMA so you can control the DAC fresh frequency without the CPU interfere.

    What do you think?

    Best regards

    Gary

  • Gary,

    Thank you for the reply. I have modified the for loop to that it toggles bit 2 on P2.

    for(;;) {
            P2OUT ^= BIT2;
            DMA0CTL |= DMAREQ;
        }

    Below is the output from the DAC on channel 1, channel 2 is the P2 (BIT2) output. In your post you asked what the signals on channels 3 and 4 where. Channel 3 is an output from an op amplifier configured as a summation amplifier with adjustable gain. The gain is set by a digital potentiometer and is fed into a second op amplifier that increases the gain even further to +/- 48V rail to rail.

    I will try your suggestion about configuring a timer to trigger the DAC.

    Thanks,

    Allan

  • I was able to configure TimerA to trigger the DMA. Below is the code I used to fix this. Thank you Gary and Bruce!

    #include <msp430.h> 
    #include <math.h>
    #include <stdlib.h>
    
    //=====================================================================================================================================================================
    //                                                                  Global Variables
    //=====================================================================================================================================================================
    unsigned char MST_Data_index = 1;
    unsigned char MST_Data[2];
    /**
     * main.c
     */
    
    void digital_pot_clt(unsigned int ctl, unsigned int val, unsigned char *ctl1, unsigned char *ctl2) {
    
        unsigned int to_convert;
        unsigned int tmp_val;
        unsigned int tmp_ctl;
        unsigned int pot_cmd;
        //0. Check if the resistance value is greater than 1023.
        if (val > 1023) {
            tmp_val = 511;
        }
        else {
            tmp_val = val;
        }
    
        //1. Check the control value.
        if (ctl <= 6 & ctl >= 0) {
            tmp_ctl = ctl << 10;
        }
        else
            tmp_ctl = 0;
    
        //2. Convert the 16 Bit Control Value to Two 8 Bit Values
        pot_cmd = tmp_ctl | tmp_val;
    
        ctl1[0] = pot_cmd;
        ctl2[0] = pot_cmd >> 8;
    
    }
    
    int main(void)
    {
        //0. Setup a sin function in memory.
        unsigned short v[26];
        //20kHz
    
        v[0] = 2046;
        v[1] = 2554;
        v[2] = 3031;
        v[3] = 3446;
        v[4] = 3772;
        v[5] = 3991;
        v[6] = 4087;
        v[7] = 4056;
        v[8] = 3898;
        v[9] = 3623;
        v[10] = 3250;
        v[11] = 2801;
        v[12] = 2305;
        v[13] = 1792;
        v[14] = 1296;
        v[15] = 846;
        v[16] = 472;
        v[17] = 196;
        v[18] = 37;
        v[19] = 3;
        v[20] = 98;
        v[21] = 315;
        v[22] = 641;
        v[23] = 1055;
        v[24] = 1531;
        v[25] = 2039;
        v[25] = 2046;
    
        //1.  ======================================= Configure the WDT to stop working =======================================.
        WDTCTL = WDTPW | WDTHOLD;
    
        //2. ======================================= System Clock =======================================
    
    
    
        //3.  ======================================= Configure the DAC to  =======================================,
        //a. Configure the input range to full scale output.
        DAC12_0CTL0 = DAC12IR;
        //b. Configure the DAC reference voltage to AVCC.
        DAC12_0CTL0 |= DAC12SREF_1;
        //c. Configure the DAC Amplifier Setting -> Input Buffer: HS/HC & Output Buffer: HS/HC
        DAC12_0CTL0 |= DAC12AMP_5;
        //d. Enable Conversion.
        DAC12_0CTL0 |= DAC12ENC;
        //e. Turn on Calibration.
        DAC12_0CTL0 |= DAC12CALON;
        //f. Select the load trigger for the DAC.
        //DAC12_0CTL0 |= DAC12LSEL1;
        //g. Turn on the dac ie. //DAC12IFG will not be set if this is enabled.
        //DAC12_0CTL0 |= DAC12IE;
    
    
        //3. ======================================= Configure the DMA controller  =======================================
        //a. Source address.
        __data16_write_addr((unsigned short) &DMA0SA, (unsigned long) &v[0]);
        //b. Destination Address
        __data16_write_addr((unsigned short) &DMA0DA, (unsigned short) &DAC12_0DAT);
        //c. Set the block size.
        DMA0SZ = 25;
        //d. Repeated Single Transfer.
        DMA0CTL = DMADT_5;
        //e.  Source address is incremented.
        DMA0CTL |= DMASRCINCR_3;
        //f. Destination address is unchanged.
        DMA0CTL |= DMADSTINCR_0;
        //g. Enable DCA Interrupt
        DMACTL0 |= DMA0TSEL_1;
        //h. Enable DMA0
        DMA0CTL |= DMAEN;
        //DAC12_0CTL0 = DAC12IFG;
    
        //4. ======================================= Configure the Timer A0 controller  =======================================
        //a. CCR0 interrupt enabled
        TA0CCTL0 = CM1 + OUTMOD2;
        TA0CCR0 = 1;
        //b. SMCLK, upmode, clear TAR
        TA0CTL = TASSEL_2 + MC_1 + TACLR;
    
    
        //5.  ======================================= SPI Configuration  =======================================
        //a. Configure the pins for SPI output
        //i. Port 8 Pins,
        //PIN1 (UCA1CLK)
        //PIN2 (UCA1SIMO)
        //PIN3 (UCA1SOMI)
        P8SEL = 0b00001110;
        P8DIR = 0b00000000;
    
        //ii. Port 2 Pins
        //===PIN2 U10 RST===
        //Set the direction.
        P2DIR = 0b00000100;
        //Set the pull up resistor (disable).
        P2REN = 0b00000000;
        //Set the drive strength (full).
        P2DS = 0b00000100;
        //Set the pin function (gpio).
        P2DS = 0b00000000;
        P2OUT = BIT2;
        //===PIN0 U10 SYNC===
        //Set the direction.
        P2DIR |= 0b00000001;
        //Set the pull up resistor (disable).
        P2REN |= 0b00000000;
        //Set the drive strength (full).
        P2DS |= 0b00000001;
        //Set the pin function (gpio).
        P2DS |= 0b00000000;
        P2OUT |= BIT0;
        //===PIN1 U10 RDY===
        //Set the direction.
        P2DIR |= 0b00000000;
        //Set the pull up resistor (enable).
        P2REN |= 0b00000000;
        //Set the drive strength (full).
        P2DS |= 0b00000000;
        //Set the pin function (gpio).
        P2DS |= 0b00000000;
    
        //iii. Univ. Serial Comm Module (SPI)
        // **Put state machine in reset**
        UCA1CTL1 |= UCSWRST;
        // 3-pin, 8-bit SPI master
        // Clock polarity high, MSB
        UCA1CTL0 |= UCMST|UCSYNC|UCCKPL|UCMSB;
        // SMCLK
        UCA1CTL1 |= UCSSEL_2;
        // /2
        UCA1BR0 = 0x02;
        UCA1BR1 = 0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      ;
        // No modulation
        UCA1MCTL = 0;
        // **Initialize USCI state machine**
        UCA1CTL1 &= ~UCSWRST;
        // Enable USCI_A0 RX,TX interrupt
        //UCA1IE = UCRXIE;
        //iv. Setup the SYNC POT input.
        P2OUT |= 0;
    
        //v. Wait for slave to initialize
        __delay_cycles(100);
    
        //vi. Create the POT data.
        digital_pot_clt(4, 1, &MST_Data[0], &MST_Data[1]);
    
        //vii. Send the POT data.
        while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
         UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character
        MST_Data_index--;
        while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
              UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character
    
        P2OUT &= BIT2;
    
        P2OUT |= 0;
    
       //v. Wait for slave to initialize
       __delay_cycles(100);
    
       //vi. Create the POT data.
       digital_pot_clt(2, 512, &MST_Data[0], &MST_Data[1]);
    
       //vii. Send the POT data.
       while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
        UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character
       MST_Data_index--;
       while (!(UCA1IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
             UCA1TXBUF = MST_Data[MST_Data_index];                     // Transmit first character
    
           P2OUT &= BIT2;
    
       //viii. Global Interrupt Enable
       __bis_SR_register(GIE);
    
      __no_operation();
    
    }
    
    // Timer0 A0 interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void TIMER0_A0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) TIMER0_A0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
        P2OUT ^= BIT2;
       //DMA0CTL |= DMAREQ;
    }
    
    

    Increasing the number of samples in the v[] array would remove crossover distortion, but would change the frequency of the sine wave to 10kHz.

**Attention** This is a public forum