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
}
//------------------------------------------------------------------------------