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.

How trasfer data from DMA to Uart interface

Other Parts Discussed in Thread: MSP430FG4618

Hi,

I am new for Msp430 coding. So, I need your assistances. I use MSP430FG4618.
My problem is that I record a voice and transfer it by Uart connection(RS-232) to another device (Tmote Sky). I use the sample Voice_Recorder code to record voice, but this code record the voice and playback it. So, I try to modify the Playback(void) function as read the digital data from DMA , and send to Uart interface. I am not successful for this. Please help me for this aim.

I copy/paste the example code , and color over the Playback(void) function that is needed to modify for my problem.

 

//******************************************************************************

//  MSP430FG4618/F2013 Experimenter's Board - Voice Recorder Demo

//

//  This software demonstrates voice recording and playback using an

//  MSP430FG4618 MCU. Audio is recorded and stored using in-system self-

//  programming into Flash memory until the entire device memory is

//  filled with audio data. Both recording and playback are implemented

//  using the DMA controller - allowing the CPU to be switched off (LPM0)

//  during this entire process.

//

//  ACLK = 32.768kHz, MCLK = SMCLK = DCO = default FLL = 1.048576MHz

//

//                             MSP430FG4618

//                           ------------------

//                       /|\|               XIN|-

//                        | |                  | 32kHz

//                        --|RST           XOUT|-

//                          |                  |

//              Audio Out<--|P6.5/OA2O     P5.1|-->LED

//    Sallen-Key         <--|P6.7/DAC1         |

//    Low-Pass Filter    <--|P6.3/OA1O       S4|-->  +-------------+

//    Circuitry          -->|P6.4/OA1I0     ...|-->  | LCD DISPLAY |

//                          |               S25|-->  +-------------+

//                VCC_Mic<--|P2.3              |

//    Microphone         -->|P6.0/OA0I0    P1.0|<--SW1 (Record Button)

//    Circuitry          -->|P6.2/OA0I1    P1.1|<--SW2 (Playback Button)

//                       <--|P6.1/OA0O         |

//

//    NOTE: Refer to the MSP430FG4618/F2013 Experimenter's Board schematic

//          for details on the external circuitry.

//

//  A. Dannenberg

//  Texas Instruments Inc.

//  Ver 1.00 - October 2006

//  Built with IAR Embedded Workbench Version: 3.42A

//******************************************************************************

#include "msp430xG46x.h"

//------------------------------------------------------------------------------

// Voice-recorder memory definitions

//

// Two memory ranges are defined for voice recording. The MSP430FG4618 device

// memory is split into to regions as the device's interrupt vectors are

// located in the middle of the MSP430FG4618 Flash memory and must not be

// overwritten.

//

// ATTN: Care must be taken not to conflict with memory used by the program

//       code. Also both addresses need to be integer multipliers of 0x0200

//       due to the Flash memory segmenting.

//------------------------------------------------------------------------------

#define Memstart             0x6000         // Memory range to be filled with

#define Memend               0xfc00         // sampled data for voice recorder

 

#define Memstart2            0x10000        // Memory range to be filled with

#define Memend2              0x20000        // sampled data for voice recorder

 

#define SamplePrd            118            // Record&playback sample period

                                            // SampleR = 1MHz / SamplePrd

//------------------------------------------------------------------------------

// LCD segment definitions

//------------------------------------------------------------------------------

#define SEG_A                0x01

#define SEG_B                0x02

#define SEG_C                0x04

#define SEG_D                0x08

#define SEG_E                0x40

#define SEG_F                0x10

#define SEG_G                0x20

#define SEG_H                0x80

//------------------------------------------------------------------------------

// The following two variables contain the control register settings for DMA2

// for the record and playback. DMA1 is used to transfer these control register

// values into the control register of DMA2 to start the DMA2 operation.

//

// Note that the value for record is kept in RAM to allow accessing it while

// a Flash write operation is pending. This is not needed for playback.

// Also, the modifier '__root' is used to prevent any compiler optimization.

//------------------------------------------------------------------------------

__root unsigned int DMA2CTL_Const_R = DMADSTINCR_3 + DMAEN + DMAIE;

                                            // Single transfer,

                                            // increment dest. address,

                                            // leave source address unchanged,

                                            // src and dst are words size,

                                            // edge sensitive DMA trigger,

                                            // enable DMA, enable DMA int

 

__root const unsigned int DMA2CTL_Const_P = DMASRCINCR_3 + DMAEN + DMAIE;

                                            // Single transfer,

                                            // leave dest. address unchanged,

                                            // increment source address,

                                            // src and dst are words size,

                                            // edge sensitive DMA trigger,

                                            // enable DMA, enable DMA int

//------------------------------------------------------------------------------

// Function prototypes

//------------------------------------------------------------------------------

void Record(void);

void Playback(void);

void Erase(void);

//------------------------------------------------------------------------------

void main(void)

{

  volatile unsigned int i;

 

  // WDT+ & LFXT1

  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

  FLL_CTL0 |= XCAP14PF;                     // Configure load caps

 

  // LFXT1 startup delay

  do

  {

    IFG1 &= ~OFIFG;                         // Clear OSCFault flag

    for (i = 0x47FF; i > 0; i--);           // Time for flag to set

  }

  while (IFG1 & OFIFG);                     // OSCFault flag still set?

 

  // Ports

  P1OUT = 0;                                // All P1.x reset

  P1IE = 0x03;                              // P1.0, P1.1 Interrupt enabled

  P1IES = 0x03;                             // P1.0, P1.1 hi/low edge

  P1DIR = 0xFC;                             // P1.0/1 = input (switches)

  P2OUT = 0;                                // All P2.x reset

  P2DIR = 0xDF;                             // UCA0RXD = inp

  P3OUT = 0x20;                             // All P3.x reset (3.5 = buzzer)

  P3DIR = 0xF9;                             // I2C pins = inp

  P4OUT = 0;                                // All P4.x reset

  P4DIR = 0xFF;                             // All P4.x outputs

  P5OUT = 0;                                // All P5.x reset

  P5SEL = 0x1C;                             // P5.2/3/4 = LCD COM lines

  P5DIR = 0xFF;                             // All P5.x outputs

  P6OUT = 0;                                // All P6.x reset

  P6SEL = 0xBF;                             // All but P6.6 analog funct.

  P6DIR = 0xFF;                             // All P6.x outputs

  P7OUT = 0;                                // All P7.x reset

  P7DIR = 0xFF;                             // All P7.x outputs

  P8OUT = 0;                                // All P8.x reset

  P8DIR = 0xFF;                             // All P8.x outputs

  P9OUT = 0;                                // All P9.x reset

  P9DIR = 0xFF;                             // All P9.x outputs

  P10OUT = 0;                               // All P10.x reset

  P10DIR = 0xFF;                            // All P10.x outputs

 

  // LCD_A

  for (i = 19; i > 0; i--) LCDMEM[i] = 0;   // Clear LCD

  LCDACTL = LCDON + LCD4MUX + LCDFREQ_128;  // 4mux LCD, ACLK/128

  LCDAPCTL0 = 0x7E;                         // Segments 4-27

 

  while (1)                                 // Repeat forever

  {

    P1IFG &= ~0x03;                         // Clear pending button interrupts

    P1IE |= 0x03;                           // Enable interrupts for buttons

 

    // Wait for event, hold CPU in low-power mode 4

    __bis_SR_register(LPM4_bits + GIE);

    __disable_interrupt();

 

    // Process key-press event

    if (P1IFG & 0x02)                       // Record button SW2 pressed?

      Record();

    else if (P1IFG & 0x01)                  // Playback button SW1 pressed?

      Playback();

  }

}

//------------------------------------------------------------------------------

// Record audio data and store into Flash memory using the ADC12 module and

// the integrated DMA controller.

//------------------------------------------------------------------------------

void Record(void)

{

  // Power-up external hardware

  P5OUT |= 0x02;                            // LED#4 on

  P2OUT |= 0x08;                            // Mic supply on

 

  // Setup OA0 = Microphone pre-amplifier

  // OA0+ = P6.2/OA0I1

  // OA0- = P6.0/OA0I0

  // OA0OUT = P6.1/OA0O, A1 (internal)

  OA0CTL0 = OAP_1 + OAPM_3;                 // Select inputs, power mode

  OA0CTL1 = OARRIP;                         // General purp., rail-to-rail inp.

 

  // Setup ADC12 module

  ADC12CTL0 = ADC12ON;                      // Turn on ADC12, S&H in sample

                                            // ADC12 Clock=ADC12OSC

  ADC12CTL1 = SHS_3 + CONSEQ_2;             // S&H src select: Timer_B.OUT1,

                                            // rep. single channel

  ADC12IFG = 0x00;                          // Clear ADC12 interrupt flag reg

  ADC12MCTL0 = 0x0001;                      // Input channel A1

  ADC12CTL0 |= ENC;                         // Enable conversion

 

  // Steps executed for automated ADC12-to-Flash transfer

  // everything without CPU intervention

  //

  // (1) Timer_B.OUT1 triggers ADC12 conversion

  // (2) ADC12IFGx triggers DMA transfer

  // (3) Goto (1) until DMA0SZ = 0

 

  // Setup Timer_B for recording

  TBCTL = TBSSEL_2;                         // Use SMCLK as Timer_B source

  TBR = 0;

  TBCCR0 = SamplePrd;                       // Initialize TBCCR0

  TBCCR1 = SamplePrd - 20;                  // Trigger for ADC12 SC

  TBCCTL1 = OUTMOD_7;                       // Reset OUT1 on EQU1, set on EQU0

 

  // Setup the DMA controller

  //

  // To allow for recording into the whole device memory without CPU

  // interaction, and without overwriting the interrupt vectors, all three

  // DMA channels are used in a daisy-chained fashion.

  //

  // (1) DMA0 fills up one block of MSP430 Flash memory

  // (2) After this, DMA1 loads the control register of DMA2

  // (3) DMA2 fills another block of MSP430 Flash memory

 

  // Configure DMA triggers first

  DMACTL0 = DMA2TSEL_6 +                    // ADC12IFGx triggers DMA2

            DMA1TSEL_14 +                   // DMA0IFG triggers DMA1

            DMA0TSEL_6;                     // ADC12IFGx triggers DMA0

 

  // Setup DMA0 for recording to first memory block

  DMA0SA = (unsigned int)&ADC12MEM0;        // Src address = ADC12 module

  DMA0DA = Memstart;                        // Dst address = Flash memory

  DMA0SZ = (Memend - Memstart) >> 1;        // Size in words

  DMA0CTL = DMADSTINCR1 + DMADSTINCR0 + DMAEN;

                                            // Single transfer,

                                            // increment dest. address,

                                            // leave source address unchanged,

                                            // src and dst are words size,

                                            // edge sensitive DMA trigger,

                                            // enable DMA

 

  // Setup DMA1 for activating DMA2

  DMA1SA = (unsigned int)&DMA2CTL_Const_R;  // Src address = contents to load

  DMA1DA = (unsigned int)&DMA2CTL;          // Dst address = into DMA2CTL

  DMA1SZ = 1;                               // 1 Transfer

  DMA1CTL = DMAEN;                          // Single transfer, enable DMA

 

  // Setup DMA2 for recording to second memory block

  DMA2SA = (unsigned int)&ADC12MEM0;        // Src address = ADC12 module

  __data16_write_addr((unsigned short)&DMA2DA, Memstart2);

                                            // Dst address = Flash memory,

                                            // Use intrinsic to ensure single-

                                            // access to control register

  DMA2SZ = (Memend2 - Memstart2) >> 1;      // Size in words

 

  // Setup and erase Flash memory

  // (Rem.: This time is also used to wait for

  //        the voltages getting stabilized)

  FCTL2 = FWKEY + FSSEL1 + FN1;             // SMCLK/3 = ~333kHz

  FCTL3 = FWKEY;                            // Unlock Flash memory for write

  Erase();                                  // Call Flash erase subroutine

  FCTL1 = FWKEY + WRT;                      // Enable Flash write for recording

 

  // Update LCD

  LCDM8 = SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G;  // "R"

  LCDM7 = SEG_A + SEG_D + SEG_E + SEG_F + SEG_G;          // "E"

  LCDM6 = SEG_A + SEG_D + SEG_E + SEG_F;                  // "C"

  LCDM5 = 0x00;                             // " "

  LCDM4 = 0x00;                             // " "

 

  // Start recording

  P1OUT |= 0x01;                            // LED#4 on

  TBCTL |= MC0;                             // Start Timer_B in UP mode

                                            // (counts up to TBCL0)

 

  // Activate LPM during DMA recording, wake-up when finished

  __bis_SR_register(LPM0_bits + GIE);       // Enable interrupts, enter LPM0

  __disable_interrupt();                    // Disable interrupts

 

  // Deactivate Flash memory write access

  FCTL1 = FWKEY;                            // Disable Flash write

  FCTL3 = FWKEY + LOCK;                     // Lock Flash memory

 

  // Power-down MSP430 modules

  ADC12CTL1 &= ~CONSEQ_2;                   // Stop conversion immediately

  ADC12CTL0 &= ~ENC;                        // disable ADC12 conversion

  ADC12CTL0 = 0;                            // Switch off ADC12 & ref voltage

  TBCTL = 0;                                // Disable Timer_B

  OA0CTL0 = 0;                              // Disable OA0

 

  P2OUT &= ~0x08;                           // Mic supply off

  P5OUT &= ~0x02;                           // LED#4 off

 

  // Update LCD

  LCDM8 = 0x00;                             // " "

  LCDM7 = 0x00;                             // " "

  LCDM6 = 0x00;                             // " "

}

//------------------------------------------------------------------------------

// Playback audio data stored in Flash memory using the integrated

// DMA controller and DAC12 module.

//------------------------------------------------------------------------------

void Playback(void)

{

  volatile unsigned int i;


  // Update LCD

  LCDM8 = SEG_A + SEG_B + SEG_E + SEG_F + SEG_G;          // "P"

  LCDM7 = SEG_D + SEG_E + SEG_F;                          // "L"

  LCDM6 = SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G;  // "A"

  LCDM5 = SEG_B + SEG_C + SEG_F + SEG_G;                  // "Y"

  LCDM4 = 0x00;                             // " "


  // Power-up external hardware

  P5OUT |= 0x02;                            // LED#4 on


  // Setup DAC12_0 = Offset for OA2 gain state

  DAC12_0CTL = DAC12IR + DAC12AMP_2 + DAC12ENC + DAC12OPS;

  DAC12_0DAT = 0x057F;                      // Offset level


  // Setup OA1 = S-K Output filter for DAC12_1

  // OA1+ = P6.4/OA1I0

  // OA1- = R_Bottom (internal)

  // OA1OUT = P6.3/A3/OA1O, R_Bottom (internal)

  OA1CTL0 = OAPM_3 + OAADC1;                // Select inputs, power mode

  OA1CTL1 = OAFC_1 + OARRIP;                // Unity Gain, rail-to-rail inputs


  // Setup OA2 = Gain stage

  // OA2+ = DAC12_0OUT

  // OA2- = OA1OUT

  // OA2OUT = P6.5/OA2O

  OA2CTL0 = OAN_2 + OAP_2 + OAPM_3 + OAADC1;// Select inputs, power mode

  OA2CTL1 = OAFC_6 + OAFBR_2 + OARRIP;      // Invert. PGA, OAFBRx sets gain


  // Setup DAC12_1 module

  ADC12CTL0 = REFON + REF2_5V;              // ADC12 ref needed for DAC12s

  DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12LSEL_3 + DAC12ENC;

                                            // Configure DAC12

                                            // latch data on pos. Timer_B.OUT2


  for (i = 0; i < 0x3fff; i++);             // Wait until voltages have stab.


  // Steps executed for automated Flash-to-DAC12 transfer

  // everything without CPU intervention

  //

  // (1) Timer_B.CCIFG2 triggers DMA transfer

  // (2) Timer_B.OUT2 triggers DAC12 data latch

  // (3) Goto (1) until DMA0SZ = 0


  // Setup Timer_B for playback

  TBCTL = TBSSEL_2;                         // Use SMCLK as Timer_B source

  TBCCR0 = SamplePrd;                       // Initialize TBCCR0 w/ sample prd

  TBCCR2 = SamplePrd >> 1;                  // EQU2 will trigger DMA

  TBCCTL2 = OUTMOD_7;                       // Reset OUT2 on EQU2, set on EQU0


  // Setup the DMA controller

  //

  // To allow for playback from the whole device memory without CPU

  // interaction, all three DMA channels are used in a daisy-chained fashion.

  //

  // (1) DMA0 reads one block of MSP430 Flash memory

  // (2) After this, DMA1 loads the control register of DMA2

  // (3) DMA2 reads another block of MSP430 Flash memory


  // Configure DMA triggers first

  DMACTL0 = DMA2TSEL_2 +                    // Timer_B.CCIFG2 triggers DMA2

            DMA1TSEL_14 +                   // DMA0IFG triggers DMA1

            DMA0TSEL_2;                     // Timer_B.CCIFG2 triggers DMA0


  // Setup DMA0 for playback from first memory block

  DMA0SA = Memstart;                        // Src address = Flash memory

  DMA0DA = (unsigned int)&DAC12_1DAT;       // Dst address = DAC12 module

  DMA0SZ = (Memend - Memstart) >> 1;        // DMA block size

  DMA0CTL = DMASRCINCR1 + DMASRCINCR0 + DMAEN;

                                            // Single transfer,

                                            // increment source address,

                                            // leave dest. address unchanged,

                                            // src and dst are words size,

                                            // edge sensitive DMA trigger,

                                            // enable DMA


  // Setup DMA1 for activating DMA2

  DMA1SA = (unsigned int)&DMA2CTL_Const_P;  // Src address = contents to load

  DMA1DA = (unsigned int)&DMA2CTL;          // Dst address = into DMA2CTL

  DMA1SZ = 1;                               // 1 Transfer

  DMA1CTL = DMAEN;                          // Single transfer, enable DMA


  // Setup DMA2 for playback from second memory block

  __data16_write_addr((unsigned short)&DMA2SA, Memstart2);

                                            // Src address = Flash memory

                                            // Use intrinsic to ensure single-

                                            // access to control register

  DMA2DA = (unsigned int)&DAC12_1DAT;       // Dst address = DAC12 module

  DMA2SZ = (Memend2 - Memstart2) >> 1;      // DMA block size


  // Start playback

  TBCTL |= MC0;                             // Start Timer_B in UP mode

                                            // (counts up to TBCCR0)


  // Activate LPM during DMA playback, wake-up when finished

  __bis_SR_register(LPM0_bits + GIE);       // Enable interrupts, enter LPM0

  __disable_interrupt();                    // Disable interrupts


  // Power-down MSP430 modules

  TBCTL = 0;                                // Disable Timer_B

  ADC12CTL0 = 0;                            // Switch off ADC12 ref voltage

  DAC12_0CTL &= ~DAC12ENC;                  // Disable DAC12 conversion

  DAC12_0CTL = 0;                           // Switch off DAC12

  DAC12_1CTL &= ~DAC12ENC;                  // Disable DAC12 conversion

  DAC12_1CTL = 0;                           // Switch off DAC12

  OA1CTL0 = 0;                              // Disable OA1

  OA2CTL0 = 0;                              // Disable OA2


  P5OUT &= ~0x02;                           // LED#4 off


  // Update LCD

  LCDM8 = 0x00;                             // " "

  LCDM7 = 0x00;                             // " "

  LCDM6 = 0x00;                             // " "

  LCDM5 = 0x00;                             // " "

}

//------------------------------------------------------------------------------

// Erase Flash memory for new recording

//------------------------------------------------------------------------------

void Erase(void)

{

  unsigned int Ptr = Memstart;              // Start of record memory array

  unsigned long FarPtr = Memstart2;

 

  // Update LCD

  LCDM8 = SEG_A + SEG_D + SEG_E + SEG_F + SEG_G;          // "E"

  LCDM7 = SEG_E + SEG_G;                                  // "R"

  LCDM6 = SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G;  // "A"

  LCDM5 = SEG_A + SEG_C + SEG_D + SEG_F + SEG_G;          // "S"

  LCDM4 = SEG_A + SEG_D + SEG_E + SEG_F + SEG_G;          // "E"

 

  // Erase memory block from 'Memstart' to 'Memend'

  do

  {

    if (Ptr & 0x1000)                       // Use bit 12 to toggle LED#4

      P5OUT |= 0x02;

    else

      P5OUT &= ~0x02;

 

    FCTL1 = FWKEY + ERASE;

    *(unsigned char *)Ptr = 0x00;           // Dummy write to activate

                                            // segment erase

    Ptr += 0x0200;                          // Point to next segment

  } while (Ptr < Memend);

 

  // Erase memory block from 'Memstart2' to 'Memend2'

  do

  {

    if (FarPtr & 0x1000)                    // Use bit 12 to toggle LED#4

      P5OUT |= 0x02;

    else

      P5OUT &= ~0x02;

 

    FCTL1 = FWKEY + ERASE;

    __data20_write_char(FarPtr, 0x00);      // Dummy write to activate

                                            // segment erase

    FarPtr += 0x0200;                       // Point to next segment

  } while (FarPtr < Memend2);

}

//------------------------------------------------------------------------------

// PORT1 interrupt handler

//------------------------------------------------------------------------------

#pragma vector=PORT1_VECTOR

__interrupt void Port1_ISR (void)

{

  P1IE &= ~0x03;                            // Disable button interrupts

  __bic_SR_register_on_exit(LPM4_bits);     // Exit LPM4 on reti to

                                            // Activate voice recorder

}

//------------------------------------------------------------------------------

// DMA interrupt handler

//------------------------------------------------------------------------------

#pragma vector=DMA_VECTOR

__interrupt void DMA_ISR(void)

{

  DMA2CTL &= ~DMAIFG;                       // Clear DMA2 interrupt flag

  __bic_SR_register_on_exit(LPM0_bits);     // Exit LPM0 on reti

}

//------------------------------------------------------------------------------

  • To write to the UART instead of the DAC, you'll need to change:

    1. The destination address of DMA0 and DMA2.  Write to TXBUF.

    and

    2. The trigger for DMA0 and DMA2.  Trigger on TXIFG.

    and

    3. The addressing mode for DMA0 and DMA2.  Use source byte, destination byte.

    and

    4. The size of the transfers for DMA0 and DMA2.  They are now twice the size.  (Bytes instead of words.)

     

    All of these changes belong in the area you already highlighted.

    Jeff

     

  • Thanks to answer Jeff. Can you point where i should change ? I am not a msp430 coder , i need this code for another project (about Telosb Project). i need the digital sound data , in this case i try to transfer digital data to telosb by serial connection. So, I do not know exactly what i should do about msp430 to do this aim.

    i understand the below part of the code must change. i change the destination address (not sure if it is correct ?) , but i am not sure how do the other steps. can you help me on code please?

     

    // Setup Timer_B for playback

      TBCTL = TBSSEL_2;                         // Use SMCLK as Timer_B source

      TBCCR0 = SamplePrd;                       // Initialize TBCCR0 w/ sample prd

      TBCCR2 = SamplePrd >> 1;                  // EQU2 will trigger DMA

      TBCCTL2 = OUTMOD_7;                       // Reset OUT2 on EQU2, set on EQU0


      // Setup the DMA controller

      //

      // To allow for playback from the whole device memory without CPU

      // interaction, all three DMA channels are used in a daisy-chained fashion.

      //

      // (1) DMA0 reads one block of MSP430 Flash memory

      // (2) After this, DMA1 loads the control register of DMA2

      // (3) DMA2 reads another block of MSP430 Flash memory


      // Configure DMA triggers first

      DMACTL0 = DMA2TSEL_2 +                    // Timer_B.CCIFG2 triggers DMA2

                DMA1TSEL_14 +                   // DMA0IFG triggers DMA1

                DMA0TSEL_2;                     // Timer_B.CCIFG2 triggers DMA0


      // Setup DMA0 for playback from first memory block

      DMA0SA = Memstart;                        // Src address = Flash memory

      DMA0DA =TXBUF;       // Dst address = DAC12 module

      DMA0SZ = (Memend - Memstart) >> 1;        // DMA block size

      DMA0CTL = DMASRCINCR1 + DMASRCINCR0 + DMAEN;

                                                // Single transfer,

                                                // increment source address,

                                                // leave dest. address unchanged,

                                                // src and dst are words size,

                                                // edge sensitive DMA trigger,

                                                // enable DMA


      // Setup DMA1 for activating DMA2

      DMA1SA = (unsigned int)&DMA2CTL_Const_P;  // Src address = contents to load

      DMA1DA = (unsigned int)&DMA2CTL;          // Dst address = into DMA2CTL

      DMA1SZ = 1;                               // 1 Transfer

      DMA1CTL = DMAEN;                          // Single transfer, enable DMA


      // Setup DMA2 for playback from second memory block

      __data16_write_addr((unsigned short)&DMA2SA, Memstart2);

                                                // Src address = Flash memory

                                                // Use intrinsic to ensure single-

                                                // access to control register

      DMA2DA = TXBUF;       // Dst address = DAC12 module

      DMA2SZ = (Memend2 - Memstart2) >> 1;      // DMA block size


      // Start playback

      TBCTL |= MC0;                             // Start Timer_B in UP mode

                                                // (counts up to TBCCR0)


      // Activate LPM during DMA playback, wake-up when finished

      __bis_SR_register(LPM0_bits + GIE);       // Enable interrupts, enter LPM0

      __disable_interrupt();                    // Disable interrupts

  • Jeff Tenney said:
    To write to the UART instead of the DAC, you'll need to change:

    I fear it's not as easy. In the original setup, the 'clocking' comes from solely the ADC. (there are no timing restrictions on the destination). Also, the source and the destination can be read/written as words.

    If you want to pass from ADC to UART, there are two problems. First, you need to wait until something is converted (else you would senddoubles) but then you need to wait until it can be sent (this can be circumvented by carefully chosing sample rates and baudrate). But the second is that the source is 16 bit, and the detination can only be written to 8 bit (and requires two transfers). This makes things extremely difficult.
    it's no unsolveable problem to trigger on the conversion, as long as the UART is faster than required. If the UART is idle, it won't be a problem.
    But since you have to split the transfer in two byte transfers, you'll have to wait for the ADC and then for the UARTs second byte. This is really tricky. It will only work if the ADC sampling frequency and the UAR sending time for two bytes do match 100,00%. Else you'll eitehr occasionally miss conversion results or will overrun the sending (depending on the implementation).

    I think, the easiest way would be to sample to one of two RAM buffers using one DMA and another DMA transfers the content of the already filled buffer to the UART. Software intervention is needed when the buffers need to be switched (maybe only for the UART).

    The demo code has one pitfall: on some MSPs, it is impossible to program the DMA using DMA. So the trick of configuring DMA2 by DMA1 (triggered by DMA0) won't work on e.g. the 5x processors (and maybe others too).

    A trick could be: setup two DMA channels for the same job, but let the second one only do 'dummy writes' to a memory location. Make the second DMAs transfer length shorter than the 'real ones' and let it triger an ISR. This way, the ISR has been called (and the MSP awakened) before the real DMA transfer is done. If configured carefully, the ISR can do busy waiting for the real transfer to complete and set  it up for the next run (buffer address switch) before it is triggered next time.

    In any case, DMA transfers need to activate MCLK, so with active DMA transfers you don't save as much power as one could think.

  • Haken,

    There is enough involved here that I can't give you the actual code.  I hope you understand.  You also need to configure the UART, trigger the first transfer manually, and eliminate unnecessary / wasteful code related to the timers, the DAC, the OA, etc.  Then there's the requirements imposed by the remote end (ie, is little endian OK for the 16-bit samples? etc.)

    @JMG, the recording phase is already done when it's time to play back.  The data is sitting in two large blocks of flash memory.  It needs to be sent from flash to the UART.

    Jeff

  • Jeff Tenney said:
    @JMG, the recording phase is already done when it's time to play back.  The data is sitting in two large blocks of flash memory.  It needs to be sent from flash to the UART.

    Oops, then I misunderstood the problem. Sorry. I didn't look at the code too close (I only have small time windows in which I can switch to the browser and read/write something, often in small chunks). If only plain FLASH-to-UART transfer is required, then it's of course by far not as complex as I wrote. Flash has no timing requirements and can provide byte values even if the data is words. Endianess is, however, a possible problem, but this can be addresed before storing the data oin the flash.

  • hi, 

    i have changed the playback() function with below code, but it was not successful code. Please help me for what is wrong. 

     

     

    UCA0CTL1 |= UCSWRST;      //Configure the USCI with the reset bit held high

       P4SEL &= ~0x0C0;          //P4.7,6 != USCI_A0 RXD/TXD

       P2SEL |= 0x30;            //Set the USCI to use P2.4 and P2.5 for RX/TX

       UCA0CTL1 |= UCSSEL_2;     //Use SMCLK

       UCA0BR0 = 0x45;           //Set Bit Rate to 115200bps with a 8Mhz clock

       UCA0BR1 = 0x00;

       UCA0MCTL = 0x4A;          //Modulation

       UCA0CTL1 &= ~UCSWRST;     //Done configuring so take USCI out of reset

       IE2 |= UCA0RXIE;          //Enable USCI_A0 RX interrupt

      // Setup the DMA controller

      //

      // To allow for playback from the whole device memory without CPU

      // interaction, all three DMA channels are used in a daisy-chained fashion.

      //

      // (1) DMA0 reads one block of MSP430 Flash memory

      // (2) After this, DMA1 loads the control register of DMA2

      // (3) DMA2 reads another block of MSP430 Flash memory

     

      // Configure DMA triggers first

      DMACTL0 = DMA2TSEL_4 +                    

                DMA1TSEL_14 +                   // DMA0IFG triggers DMA1

                DMA0TSEL_4;                    

     

      // Setup DMA0 for playback from first memory block

      DMA0SA = Memstart;                        // Src address = Flash memory

      DMA0DA = (int)&UCA0TXBUF;      

      DMA0SZ = (Memend - Memstart) >> 1;        // DMA block size

      DMA0CTL = DMASBDB + DMADT_4 + DMASRCINCR_3 + DMAEN; // Rpt, inc src, byte-byte

     

     

      // Setup DMA1 for activating DMA2

      DMA1SA = (unsigned int)&DMA2CTL_Const_P;  // Src address = contents to load

      DMA1DA = (unsigned int)&DMA2CTL;          // Dst address = into DMA2CTL

      DMA1SZ = 1;                               // 1 Transfer

      DMA1CTL = DMAEN;                          // Single transfer, enable DMA

     

      // Setup DMA2 for playback from second memory block

      __data16_write_addr((unsigned short)&DMA2SA, Memstart2);

     

      DMA2DA = (int)&UCA0TXBUF;       

      DMA2SZ = (Memend2 - Memstart2) >> 1;      // DMA block size

  • The DMA triggers are edge sensitive, so you'll need to manually generate the first edge.  Once all the DMA channels are set up and enabled, then do this:

    IFG2 &= ~UCA0TXIFG;
    IFG2 |= UCA0TXIFG;

    That should get the transfer(s) started.

    Also I noticed that you are still dividing the block size by 2 as if you were transferring words, but you are now transferring bytes.  (Your DMA2 code was cut off, so be sure it is transferring bytes, too.)  To fix the divide-by-2 problem, remove the ">> 1" from the DMAxSZ assignments.

    Good progress by the way!

    Jeff

  • Hi Jeff,

    Did you mean like this?  

     

     

    void Playback(void)

    {

     

     

      UCA0CTL1 |= UCSWRST;      //Configure the USCI with the reset bit held high

       P4SEL &= ~0x0C0;          //P4.7,6 != USCI_A0 RXD/TXD

       P2SEL |= 0x30;            //Set the USCI to use P2.4 and P2.5 for RX/TX

       UCA0CTL1 |= UCSSEL_2;     //Use SMCLK

       UCA0BR0 = 0x45;           //Set Bit Rate to 115200bps with a 8Mhz clock

       UCA0BR1 = 0x00;

       UCA0MCTL = 0x4A;          //Modulation

       UCA0CTL1 &= ~UCSWRST;     //Done configuring so take USCI out of reset

       IE2 |= UCA0RXIE;          //Enable USCI_A0 RX interrupt

      // Setup the DMA controller

      //

      // To allow for playback from the whole device memory without CPU

      // interaction, all three DMA channels are used in a daisy-chained fashion.

      //

      // (1) DMA0 reads one block of MSP430 Flash memory

      // (2) After this, DMA1 loads the control register of DMA2

      // (3) DMA2 reads another block of MSP430 Flash memory

     

      // Configure DMA triggers first

      DMACTL0 = DMA2TSEL_4 +                    // Timer_B.CCIFG2 triggers DMA2

                DMA1TSEL_14 +                   // DMA0IFG triggers DMA1

                DMA0TSEL_4;                     // Timer_B.CCIFG2 triggers DMA0

     

      // Setup DMA0 for playback from first memory block

      DMA0SA = Memstart;                        // Src address = Flash memory

      DMA0DA = (int)&UCA0TXBUF;       

      DMA0SZ = (Memend - Memstart) ;        // DMA block size

      DMA0CTL = DMASBDB + DMADT_4 + DMASRCINCR_3 + DMAEN; // Rpt, inc src, byte-byte

     

     

      // Setup DMA1 for activating DMA2

      DMA1SA = (unsigned int)&DMA2CTL_Const_P;  // Src address = contents to load

      DMA1DA = (unsigned int)&DMA2CTL;          // Dst address = into DMA2CTL

      DMA1SZ = 1;                               // 1 Transfer

      DMA1CTL = DMAEN;                          // Single transfer, enable DMA

     

      // Setup DMA2 for playback from second memory block

      __data16_write_addr((unsigned short)&DMA2SA, Memstart2);

                                                // Src address = Flash memory

                                                // Use intrinsic to ensure single-

                                                // access to control register

      DMA2DA = (int)&UCA0TXBUF;       

      DMA2SZ = (Memend2 - Memstart2) ;      // DMA block size

     

      IFG2 &= ~UCA0TXIFG;

      IFG2 |= UCA0TXIFG;

     

     

      // Activate LPM during DMA playback, wake-up when finished

      __bis_SR_register(LPM0_bits + GIE);       // Enable interrupts, enter LPM0

      __disable_interrupt();                    // Disable interrupts

     

     

    }

  • Yes, that's what I meant.

    Jeff

  • Jeff Tenney said:

    IFG2 &= ~UCA0TXIFG;
    IFG2 |= UCA0TXIFG;

    That should get the transfer(s) started.

    Alternatively, program the DMA for one byte less and manually push the first byte into TXBUF.

     

  • I know that this is an old thread. But i was wondering if you guys can help me.....with this...It is a similar problem. What i m trying to do is record/playback 
    some data on an external flash A25L010
    http://www.amictechnology.com/pdf/A25L010.pdf
    I m doing this through USART module in SPi 3 wire mode
    I have used the voice recorder code as example as well.. However, it is not working...I tried to step through the program but it haults 
    at the line (commented below)
    I m not sure what the problem is?? so it records data make the conversion saves it into the flash memory.I m just tackling just recording here/
    can anyone help...external flash i m using datasheet is attached above (link) thanks
    
    
    [code]
    void TimespeakRecord(void)
    {
    // Power-up external hardware
    P5OUT |= 0x02; // LED#4 on
    P2OUT |= 0x08; // Mic supply on

    OA0CTL0 = OAP_1 + OAPM_3; // Select inputs, power mode
    OA0CTL1 = OARRIP; // General purp., rail-to-rail inp.
    // Setup ADC12 module
    ADC12CTL0 = ADC12ON; // Turn on ADC12, S&H in sample
    // ADC12 Clock=ADC12OSC
    ADC12CTL1 = SHS_3 + CONSEQ_2; // S&H src select: Timer_B.OUT1,
    // rep. single channel
    ADC12IFG = 0x00; // Clear ADC12 interrupt flag reg
    ADC12MCTL0 = 0x0001; // Input channel A1
    ADC12CTL0 |= ENC; // Enable conversion


    // Setup Timer_B for recording
    TBCTL = TBSSEL_2; // Use SMCLK as Timer_B source
    TBR = 0;
    TBCCR0 = SamplePrd; // Initialize TBCCR0
    TBCCR1 = SamplePrd - 20; // Trigger for ADC12 SC
    TBCCTL1 = OUTMOD_7; // Reset OUT1 on EQU1, set on EQU0

    //USART Configuration
    U1CTL |= SWRST; //SWRST set,now intialise all registers
    U1TCTL |= SSEL1+STC+CKPL; //CKPH // SMCLK, 3-pin mode; OUT=falling edge ,IN= rising edge;
    U1CTL |= CHAR+SYNC+MM; // 8-bit SPI master
    U1BR0 = 0x02; // SMCLK/2 for baud rate //1048KHz/2
    U1BR1 = 0; // SMCLK/2 for baud rate
    ME2 |= USPIE1; // Enable USART1 SPI
    U1MCTL = 0; // Clear modulation
    U1CTL &= ~SWRST; // Initialise USART state machine

    // Setup the DMA controller

    // DMA0 fills up block of External flash memory
    P4OUT &= ~0x40; // Enable external flash (chip select of external flash connected here)
    // Configure DMA triggers first
    DMACTL0 =DMA0TSEL_10 ; // ;; URXIFG1 DMA0

    U1TXBUF = 0x00; // Dummy write to start SPI



    // Setup DMA0 for recording to first memory block
    //DMA0SA = (unsigned int)&ADC12MEM0;
    DMA0SA = (void(*)())&ADC12MEM0;// Src address = ADC12 module
    //__data16_write_addr((unsigned short)&DMA0DA, U1TXBUF);
    DMA0DA = (void(*)())&U1TXBUF; // Dst address = Flash memory
    DMA0SZ = (Memend - Memstart);
    // DMA0SZ = 0x0ffff; // Size in words
    DMA0CTL = DMADSTINCR1 + DMADSTINCR0 + DMAEN;
    // Single transfer,
    // increment dest. address,(CR1 bit 1 and CR0 bit 0)
    // leave source address unchanged,
    // src and dst are words size,
    // edge sensitive DMA trigger,
    // enable DMA

    // Setup and erase Flash memory

    //Write input of the Flash is connected to ground already ...as it is active low..so flash memory is always open.
    // FCTL2 = FWKEY + FSSEL1 + FN1; // SMCLK/3 = ~333kHz
    // FCTL3 = FWKEY; // Unlock Flash memory for write
    // Erase(); // Call Flash erase subroutine
    // FCTL1 = FWKEY + WRT; // Enable Flash write for recording

    // Update LCD
    LCDM8 = SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G; // "R"
    LCDM7 = SEG_A + SEG_D + SEG_E + SEG_F + SEG_G; // "E"
    LCDM6 = SEG_A + SEG_D + SEG_E + SEG_F; // "C"
    LCDM5 = 0x00; // " "
    LCDM4 = 0x00; // " "

    // Start recording
    TBCTL |= MC0; // Start Timer_B in UP mode
    // (counts up to TBCL0)
    // Activate LPM during DMA recording, wake-up when finished
    __bis_SR_register(LPM0_bits + GIE); // Enable interrupts, enter LPM0
    //

    // Deactivate Flash memory write access
    // FCTL1 = FWKEY; // Disable Flash write
    // FCTL3 = FWKEY + LOCK; // Lock Flash memory


    P4OUT |= 0x40; //Chips select high again (program haults here)!!!

    // Power-down MSP430 modules
    ADC12CTL1 &= ~CONSEQ_2; // Stop conversion immediately
    ADC12CTL0 &= ~ENC; // disable ADC12 conversion
    ADC12CTL0 = 0; // Switch off ADC12 & ref voltage
    TBCTL = 0; // Disable Timer_B
    OA0CTL0 = 0; // Disable OA0

    P2OUT &= ~0x08; // Mic supply off
    P5OUT &= ~0x02; // LED#4 off

    // Update LCD
    LCDM8 = 0x00; // " "
    LCDM7 = 0x00; // " "
    LCDM6 = 0x00; // " "
    }

**Attention** This is a public forum