Forums

Timer_A and Timer_B Sync

Started by Ederson Cichaczewski July 24, 2008
Hi,
I want to measure the phase delay in an analog circuit applying a 50KHz sine wave generated in DAC (that access a table using DMA) and read this same signal with the ADC of the MSP430F156 microcontroller. I want to reconstruct the sine wave read with 160 points, so the ADC speed doesn't support sample the 50KHz sine wave, however, I'm using a technique that I read 160 sine wave cicles and get one sample of each cicle incrementing the point of sampling. I am using timer_A to generate clock for DAC output the sine wave and Timer_B to start A/D conversions in each point of the sine wave incrementing TBCCR1. I start the phase measure by software with RS232 communication, so when the firmware detects a start command from the software, it starts a measure generating the sine wave and, at the same time, reading it back.
My problem is the start of both timers. I am starting timer_B in the next line of timer_A start, but Timer_B does not start always in the same count of timer_A, and because that, the measure of phase delay between sine wave generated and sine wave read is not always the same. I'm not understanding what is happening.
The most important part of the code follows below.
Could somebody help me?
Thanks in advance,
Ederson
----------
#include
void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;
  /*Initialization of variables...*/
 
  BCSCTL1 &= ~XT2OFF;                   // XT2= HF XTAL
  do
  {
  IFG1 &= ~OFIFG;                
  for (i = 0xFF; i > 0; i--);          
}
  while ((IFG1 & OFIFG));             
  BCSCTL2 |= SELM_2 + SELS;             // MCLK= XT2  
  UCTL0 |= CHAR;                        // 8-bit character
  UTCTL0 |= SSEL0 + SSEL1;              // UCLK = SMCLK
  UBR00 = 0x41;                         // 8Mhz/9600
  UBR10 = 0x03;                         //
  UMCTL0 = 0x92;                        // no modulation
  ME1 |= UTXE0 + URXE0;                 // Enable USART0 TXD/RXD
  UCTL0 &= ~SWRST;                      // Initialize USART state machine
  IE1 |= URXIE0;                        // Enable USART0 RX interrupt   
 
  ADC12CTL0 = SHT0_0 + REF2_5V + REFON; 
  ADC12MCTL0 = SREF_1 +INCH_4 + EOS;    // VR+ = Vref+, VR- = AVss, A4 (P6.4)
  ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP + ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
  ADC12CTL0 |= ADC12ON + ENC;              

  DMACTL0 = DMA0TSEL_5;                 // DAC12IFG trigger DMA
  
// Setup DMA0
  DMA0SA = (int) Sin_tab;               
  DMA0DA = DAC12_0DAT_;                 
  DMA0SZ = 32;                         
  DMA0CTL = DMADT_4 + DMASRCINCR_3;// + DMAIE; 
  DMA0CTL |= DMAEN;                    
//Setup DAC
  DAC12_0CTL = DAC12LSEL_2 + DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
  DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1 1V25 ref voltage
  DAC12_0CTL |= DAC12ENC;               //  DAC0
  DAC12_1CTL |= DAC12ENC;               //  DAC1
  do{}while(DAC12_0CTL & DAC12CALON == 1); 
  do{}while(DAC12_1CTL & DAC12CALON == 1); 
  DAC12_1DAT = 2048;                    // DAC1: ref 1V25 = 2V5/2
//Setup Timer_A
  TACCTL1 = OUTMOD_3;                
  TACCR1 = 2;                           // CCR1 PWM Duty Cycle 
  TACCR0 = 4;                            
//Setup Timer_B
  TBCCTL1 = OUTMOD_3;                   
  TBCCR1 = 1;                            
  TBCCR0 = 159;                         
 
//Turn Off CPU forever
  _BIS_SR(LPM1_bits + GIE);            
}
#pragma vector=ADC_VECTOR
__interrupt void ADC12_ISR (void)
{
  signal[index] = ADC12MEM0;                               
  TBCCR1 += 1;                          // Inc TB    
  index += 1;                           // Inc vet ADC
  if(TBCCR1 == 160 && index == 159)                     // Read finished, process....
  {
/*Signal processing.....*/
/*Send results....*/
// Stop peripherals....
       TACTL &= ~MC_1;                 // stop timer A
        TBCTL &= ~MC_1;                 // stop timer B
        ADC12IE = 0x00;                     // Disable ADC interrupts  
        DMA0CTL &= ~DMAEN;                  // Disable DMA
  }
}
#pragma vector=USART0RX_VECTOR
__interrupt void usart0_rx (void)
{
  if(RXBUF0 == 65) // "A"
  {
    index = 0;
    DMA0SA = (int) Sin_tab;             
    DMA0SZ = 32;                        
    DMA0CTL |= DMAEN;                   // Enable DMA
    DAC12_0CTL |= DAC12IFG;             // Activate interrupt flag to start DAC
    DMA0CTL &= ~DMAIFG;
    ADC12IE = 0x01;                     // Enable ADC interrupts
    TBCCR1 = 1;
    TACTL |= TACLR;
    TBCTL |= TBCLR;
    // Start Timers
    TACTL = TASSEL_2 + MC_1 + ID_0;     // SMCLK, 0 to TACCR0, div clock = 1
    TBCTL = TBSSEL_2 + MC_1 + ID_0;     // SMCLK, 0 to TACCR0, div clock = 1

}
}
Novos endereços, o Yahoo! que você conhece. Crie um email novo com a sua cara @ymail.com ou @rocketmail.com.
http://br.new.mail.yahoo.com/addresses


Beginning Microcontrollers with the MSP430

Your first problem, I think, is that you move the
next ADC sample point too soon. By this I mean
that when TBCCR is hit an ADC conversion starts
and completes controlled by the (typically) 5MHz
ADC clock. On completion your ADC isr moves the
synchronous sample point forward by 1 place:
TBCCR1 += 1; // Inc TB
However, this instruction may occur before TB has
incremented again, which means potentially you
have another ADC sample started before you are
ready for it. Better to move that line of code to
where you really want it to be, that is in the TB
overflow interrupt when TB rolls over from 159 to 0.

Your second problem is the loss of synch. Are you
running this code just once, ie on receipt of an
"A", or do you want it to run every time you
receive an "A"? In that latter case, you need to
re-synch the timers A & B on detection of the
"A". Add this extra step either by just stopping
and clearing the timers using TACLR and TBCLR, or
by pre-loading the TAR and TBR counter registers
to some other known value. Of course this is
better done in the timer isr since the receipt of
the "A" start character is asynchronous to the
timer clocking, and therefore may occur as a tick
is taking place giving potential instability in
measurements. I suggest you set a flag in the rx
isr which is checked in the timer isr, which when
set stops and clears the timers and then restarts them.

I removed the spurious "" characters in the
code below for clarity. Not sure what they were ...

Hugh

At 06:08 AM 7/24/2008, you wrote:
Hi,
I want to measure the phase delay in an analog
circuit applying a 50KHz sine wave generated in
DAC (that access a table using DMA) and read this
same signal with the ADC of the MSP430F156
microcontroller. I want to reconstruct the sine
wave readwith 160 points, so the ADCspeed
doesn't support sample the 50KHz sine wave,
however, I'm using a technique that I read 160
sine wave cicles andget onesample of each
cicle incrementing the point of sampling. I am
using timer_A to generate clock for DACoutput
the sine wave and Timer_B to start A/D
conversionsin each point of the sine wave
incrementing TBCCR1. I start the phase measure by
software with RS232 communication, so when the
firmware detects a start command from the
software, it starts a measure generating the sine
wave and, at the same time, reading it back.
My problem is the start of both timers. I am
starting timer_Bin the next line of timer_A
start, butTimer_B does not start always in the
same count of timer_A, and because that, the
measure of phase delay between sine wave
generated and sine wave read is not always the
same. I'm not understanding what is happening.
The most important part of the code follows below.
Could somebodyhelp me?
Thanks in advance,
Ederson
----------

#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;
/*Initialization of variables...*/

BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
do
{
IFG1 &= ~OFIFG;
for (i = 0xFF; i > 0; i--);
}
while ((IFG1 & OFIFG));
BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
UCTL0 |= CHAR; // 8-bit character
UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
UBR00 = 0x41; // 8Mhz/9600
UBR10 = 0x03; //
UMCTL0 = 0x92; // no modulation
ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
UCTL0 &= ~SWRST; // Initialize USART state machine
IE1 |= URXIE0; // Enable USART0 RX interrupt

ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
ADC12MCTL0 = SREF_1 +INCH_4 + EOS; // VR+ = Vref+, VR- = AVss, A4 (P6.4)
ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
ADC12CTL0 |= ADC12ON + ENC;
DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA

// Setup DMA0
DMA0SA = (int) Sin_tab;
DMA0DA = DAC12_0DAT_;
DMA0SZ = 32;
DMA0CTL = DMADT_4 + DMASRCINCR_3;// + DMAIE;
DMA0CTL |= DMAEN;
//Setup DAC
DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1 1V25 ref voltage
DAC12_0CTL |= DAC12ENC; // DAC0
DAC12_1CTL |= DAC12ENC; // DAC1
do{}while(DAC12_0CTL & DAC12CALON == 1);
do{}while(DAC12_1CTL & DAC12CALON == 1);
DAC12_1DAT = 2048; // DAC1: ref 1V25 = 2V5/2
//Setup Timer_A
TACCTL1 = OUTMOD_3;
TACCR1 = 2; // CCR1 PWM Duty Cycle
TACCR0 = 4;
//Setup Timer_B
TBCCTL1 = OUTMOD_3;
TBCCR1 = 1;
TBCCR0 = 159;

//Turn Off CPU forever
_BIS_SR(LPM1_bits + GIE);
}
#pragma vector=ADC_VECTOR
__interrupt void ADC12_ISR (void)
{
signal[index] = ADC12MEM0;
TBCCR1 += 1; // Inc TB
index += 1; // Inc vet ADC
if(TBCCR1 == 160 && index ==
159) // Read finished, process....
{
/*Signal processing.....*/
/*Send results....*/
// Stop peripherals....
TACTL &= ~MC_1; // stop timer A
TBCTL &= ~MC_1; // stop timer B
ADC12IE = 0x00; // Disable ADC interrupts
DMA0CTL &= ~DMAEN; // Disable DMA
}
}
#pragma vector=USART0RX_VECTOR
__interrupt void usart0_rx (void)
{
if(RXBUF0 == 65) // "A"
{
index = 0;
DMA0SA = (int) Sin_tab;
DMA0SZ = 32;
DMA0CTL |= DMAEN; // Enable DMA
DAC12_0CTL |= DAC12IFG; //
Activate interrupt flag to start DAC
DMA0CTL &= ~DMAIFG;
ADC12IE = 0x01; // Enable ADC interrupts
TBCCR1 = 1;
TACTL |= TACLR;
TBCTL |= TBCLR;
// Start Timers
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1
TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1
}
}

Hi Hugh,

Thanks for your help.
The timer_B clock is 8MHz, so when I increment TBCCR1 in ADC isr the
TBR count is much more than TBCCR1+1, because the ADC isr is called
after the acquisition + conversion time that is 17 clock cicles of
5MHz ADC clock. I have sure that the timer_B and ADC are synchronized.
In the case of reseting timer_A and timer_B togheter, I do it in
each "A" receive. When the signal process finishes, I stop both
timers and initiates them again only when I receive an "A". Every
time that I receive "A", I have to start the measure process.
Since I stop the timers and peripherals after processing signal and I
clear and restart again the peripherals and timers only when "A"
receive, I think I don't need a timer isr to clear timer counters.
However, I implemented your suggestions, but didn't work.
I'm not understanding how to make the timers initialize always at the
same point...

--- In m..., Hugh Molesworth
wrote:
>
> Your first problem, I think, is that you move the
> next ADC sample point too soon. By this I mean
> that when TBCCR is hit an ADC conversion starts
> and completes controlled by the (typically) 5MHz
> ADC clock. On completion your ADC isr moves the
> synchronous sample point forward by 1 place:
> TBCCR1 += 1; // Inc TB
> However, this instruction may occur before TB has
> incremented again, which means potentially you
> have another ADC sample started before you are
> ready for it. Better to move that line of code to
> where you really want it to be, that is in the TB
> overflow interrupt when TB rolls over from 159 to 0.
>
> Your second problem is the loss of synch. Are you
> running this code just once, ie on receipt of an
> "A", or do you want it to run every time you
> receive an "A"? In that latter case, you need to
> re-synch the timers A & B on detection of the
> "A". Add this extra step either by just stopping
> and clearing the timers using TACLR and TBCLR, or
> by pre-loading the TAR and TBR counter registers
> to some other known value. Of course this is
> better done in the timer isr since the receipt of
> the "A" start character is asynchronous to the
> timer clocking, and therefore may occur as a tick
> is taking place giving potential instability in
> measurements. I suggest you set a flag in the rx
> isr which is checked in the timer isr, which when
> set stops and clears the timers and then restarts them.
>
> I removed the spurious "" characters in the
> code below for clarity. Not sure what they were ...
>
> Hugh
>
> At 06:08 AM 7/24/2008, you wrote:
> Hi,
> I want to measure the phase delay in an analog
> circuit applying a 50KHz sine wave generated in
> DAC (that access a table using DMA) and read this
> same signal with the ADC of the MSP430F156
> microcontroller. I want to reconstruct the sine
> wave readwith 160 points, so the ADCspeed
> doesn't support sample the 50KHz sine wave,
> however, I'm using a technique that I read 160
> sine wave cicles andget onesample of each
> cicle incrementing the point of sampling. I am
> using timer_A to generate clock for DACoutput
> the sine wave and Timer_B to start A/D
> conversionsin each point of the sine wave
> incrementing TBCCR1. I start the phase measure by
> software with RS232 communication, so when the
> firmware detects a start command from the
> software, it starts a measure generating the sine
> wave and, at the same time, reading it back.
> My problem is the start of both timers. I am
> starting timer_Bin the next line of timer_A
> start, butTimer_B does not start always in the
> same count of timer_A, and because that, the
> measure of phase delay between sine wave
> generated and sine wave read is not always the
> same. I'm not understanding what is happening.
> The most important part of the code follows below.
> Could somebodyhelp me?
> Thanks in advance,
> Ederson
> --------------------------------
--------------
>
> #include
> void main(void)
> {
> WDTCTL = WDTPW + WDTHOLD;
> /*Initialization of variables...*/
>
> BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
> do
> {
> IFG1 &= ~OFIFG;
> for (i = 0xFF; i > 0; i--);
> }
> while ((IFG1 & OFIFG));
> BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
> UCTL0 |= CHAR; // 8-bit character
> UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
> UBR00 = 0x41; // 8Mhz/9600
> UBR10 = 0x03; //
> UMCTL0 = 0x92; // no modulation
> ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
> UCTL0 &= ~SWRST; // Initialize USART state
machine
> IE1 |= URXIE0; // Enable USART0 RX
interrupt
>
> ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
> ADC12MCTL0 = SREF_1 +INCH_4 + EOS; // VR+ = Vref+, VR- =
AVss, A4 (P6.4)
> ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
> ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
> ADC12CTL0 |= ADC12ON + ENC;
>
>
> DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA
>
> // Setup DMA0
> DMA0SA = (int) Sin_tab;
> DMA0DA = DAC12_0DAT_;
> DMA0SZ = 32;
> DMA0CTL = DMADT_4 + DMASRCINCR_3;// + DMAIE;
> DMA0CTL |= DMAEN;
> //Setup DAC
> DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
> DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
> DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1 1V25 ref
voltage
> DAC12_0CTL |= DAC12ENC; // DAC0
> DAC12_1CTL |= DAC12ENC; // DAC1
> do{}while(DAC12_0CTL & DAC12CALON == 1);
> do{}while(DAC12_1CTL & DAC12CALON == 1);
> DAC12_1DAT = 2048; // DAC1: ref 1V25 = 2V5/2
> //Setup Timer_A
> TACCTL1 = OUTMOD_3;
> TACCR1 = 2; // CCR1 PWM Duty Cycle
> TACCR0 = 4;
> //Setup Timer_B
> TBCCTL1 = OUTMOD_3;
> TBCCR1 = 1;
> TBCCR0 = 159;
>
> //Turn Off CPU forever
> _BIS_SR(LPM1_bits + GIE);
> }
> #pragma vector=ADC_VECTOR
> __interrupt void ADC12_ISR (void)
> {
> signal[index] = ADC12MEM0;
> TBCCR1 += 1; // Inc TB
> index += 1; // Inc vet ADC
> if(TBCCR1 == 160 && index ==
> 159) // Read finished, process....
> {
> /*Signal processing.....*/
> /*Send results....*/
> // Stop peripherals....
> TACTL &= ~MC_1; // stop timer A
> TBCTL &= ~MC_1; // stop timer B
> ADC12IE = 0x00; // Disable ADC
interrupts
> DMA0CTL &= ~DMAEN; // Disable DMA
> }
> }
> #pragma vector=USART0RX_VECTOR
> __interrupt void usart0_rx (void)
> {
> if(RXBUF0 == 65) // "A"
> {
> index = 0;
> DMA0SA = (int) Sin_tab;
> DMA0SZ = 32;
> DMA0CTL |= DMAEN; // Enable DMA
> DAC12_0CTL |= DAC12IFG; //
> Activate interrupt flag to start DAC
> DMA0CTL &= ~DMAIFG;
> ADC12IE = 0x01; // Enable ADC interrupts
> TBCCR1 = 1;
> TACTL |= TACLR;
> TBCTL |= TBCLR;
> // Start Timers
> TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
>
>
> }
> }
>

I see that you clear the timers on receipt of the
"A", but you leave both of them running (TACLR
doesn't stop the timer) and the following TACTL
and TBCTL doesn't alter the count at that instant.

Perhaps change from this:
// Stop timers
TACTL |= TACLR;
TBCTL |= TBCLR;
// Start Timers
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1
TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1

To this:
// Stop and re-synch timers
TACTL = TASSEL_2 | MC_1 | ID_0 | TACLR; //
SMCLK, 0 to TACCR0, div clock = 1, stop
TBCTL = TBSSEL_2 | MC_1 | ID_0 | TBCLR; //
SMCLK, 0 to TACCR0, div clock = 1, stop
// Start Timers
TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock = 1
TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock = 1

The change from "+" to "|" is largely cosmetic,
but it better represents what you are trying to
achieve and can avoid some ripple errors when
incorrect definitions are used by mistake. With 2
timers, one is always started after the other so
to force them to have the same starting value you
would have to pre-load the earlier timer with a
value which increments to the required starting
value when the later timer starts. ie. how many
clock ticks are in the instruction "TBCTL="
above. If both cpu and timer are on 8MHz, then it
will be a few ticks; if the clock tick were much
slower than the cpu then there wouldn't be any. I
don't think you really care about that though, as
long as the relationship doesn't drift, but you
could pre-load TAR with (say) 4-2=2 after you
stop it but before you restart it. Look up the
assembly instruction which your compiler
generates then see how many clock cycles that requires.

The other option is to just use a single timer to
do both functions, but then of course you would
have to move the DAC CCR trigger forward each
interrupt as well as the ADC CCR trigger.

Also currently you require 160 complete DAC sine
wave cycles to acquire a complete ADC sine wave
cycle. You could reduce this drastically by
skipping ahead the appropriate minimum number of
sample points and sampling almost immediately,
instead of skipping just 1 point then waiting for
the next DAC sine wave cycle. That way you can
reduce the acquisition by an order of magnitude.

Also I assume you must calibrate the phase delay
for the ADC conversion time, along with the
front-end phase delay caused by any CR filter on
the DAC output and phase delay for extra
amplification on the ADC input. You can avoid
that calibration by making the reading
ratiometric. Use identical signal paths on both
DAC output after the filter and the measured
input, typically using a resistive divider on the
filtered output and a dual op-amp on the input
(assuming you are using an op-amp on the existing
input already). Then alternately measure the two
ADC inputs and the additional phase delay vanishes.

Hugh

At 07:14 AM 7/25/2008, you wrote:
Hi Hugh,

Thanks for your help.
The timer_B clock is 8MHz, so when I increment TBCCR1 in ADC isr the
TBR count is much more than TBCCR1+1, because the ADC isr is called
after the acquisition + conversion time that is 17 clock cicles of
5MHz ADC clock. I have sure that the timer_B and ADC are synchronized.
In the case of reseting timer_A and timer_B togheter, I do it in
each "A" receive. When the signal process finishes, I stop both
timers and initiates them again only when I receive an "A". Every
time that I receive "A", I have to start the measure process.
Since I stop the timers and peripherals after processing signal and I
clear and restart again the peripherals and timers only when "A"
receive, I think I don't need a timer isr to clear timer counters.
However, I implemented your suggestions, but didn't work.
I'm not understanding how to make the timers initialize always at the
same point...

--- In m..., Hugh Molesworth
wrote:
>
> Your first problem, I think, is that you move the
> next ADC sample point too soon. By this I mean
> that when TBCCR is hit an ADC conversion starts
> and completes controlled by the (typically) 5MHz
> ADC clock. On completion your ADC isr moves the
> synchronous sample point forward by 1 place:
> TBCCR1 += 1; // Inc TB
> However, this instruction may occur before TB has
> incremented again, which means potentially you
> have another ADC sample started before you are
> ready for it. Better to move that line of code to
> where you really want it to be, that is in the TB
> overflow interrupt when TB rolls over from 159 to 0.
>
> Your second problem is the loss of synch. Are you
> running this code just once, ie on receipt of an
> "A", or do you want it to run every time you
> receive an "A"? In that latter case, you need to
> re-synch the timers A & B on detection of the
> "A". Add this extra step either by just stopping
> and clearing the timers using TACLR and TBCLR, or
> by pre-loading the TAR and TBR counter registers
> to some other known value. Of course this is
> better done in the timer isr since the receipt of
> the "A" start character is asynchronous to the
> timer clocking, and therefore may occur as a tick
> is taking place giving potential instability in
> measurements. I suggest you set a flag in the rx
> isr which is checked in the timer isr, which when
> set stops and clears the timers and then restarts them.
>
> I removed the spurious "" characters in the
> code below for clarity. Not sure what they were ...
>
> Hugh
>
> At 06:08 AM 7/24/2008, you wrote:
> Hi,
> I want to measure the phase delay in an analog
> circuit applying a 50KHz sine wave generated in
> DAC (that access a table using DMA) and read this
> same signal with the ADC of the MSP430F156
> microcontroller. I want to reconstruct the sine
> wave readwith 160 points, so the ADCspeed
> doesn't support sample the 50KHz sine wave,
> however, I'm using a technique that I read 160
> sine wave cicles andget onesample of each
> cicle incrementing the point of sampling. I am
> using timer_A to generate clock for DACoutput
> the sine wave and Timer_B to start A/D
> conversionsin each point of the sine wave
> incrementing TBCCR1. I start the phase measure by
> software with RS232 communication, so when the
> firmware detects a start command from the
> software, it starts a measure generating the sine
> wave and, at the same time, reading it back.
> My problem is the start of both timers. I am
> starting timer_Bin the next line of timer_A
> start, butTimer_B does not start always in the
> same count of timer_A, and because that, the
> measure of phase delay between sine wave
> generated and sine wave read is not always the
> same. I'm not understanding what is happening.
> The most important part of the code follows below.
> Could somebodyhelp me?
> Thanks in advance,
> Ederson
> --------------------------------
--------------
>
> #include
> void main(void)
> {
> WDTCTL = WDTPW + WDTHOLD;
> /*Initialization of variables...*/
>
> BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
> do
> {
> IFG1 &= ~OFIFG;
> for (i = 0xFF; i > 0; i--);
> }
> while ((IFG1 & OFIFG));
> BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
> UCTL0 |= CHAR; // 8-bit character
> UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
> UBR00 = 0x41; // 8Mhz/9600
> UBR10 = 0x03; //
> UMCTL0 = 0x92; // no modulation
> ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
> UCTL0 &= ~SWRST; // Initialize USART state
machine
> IE1 |= URXIE0; // Enable USART0 RX
interrupt
>
> ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
> ADC12MCTL0 = SREF_1 +INCH_4 + EOS; // VR+ = Vref+, VR- =
AVss, A4 (P6.4)
> ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
> ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
> ADC12CTL0 |= ADC12ON + ENC;
>
>
> DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA
>
> // Setup DMA0
> DMA0SA = (int) Sin_tab;
> DMA0DA = DAC12_0DAT_;
> DMA0SZ = 32;
> DMA0CTL = DMADT_4 + DMASRCINCR_3;// + DMAIE;
> DMA0CTL |= DMAEN;
> //Setup DAC
> DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
> DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
> DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1 1V25 ref
voltage
> DAC12_0CTL |= DAC12ENC; // DAC0
> DAC12_1CTL |= DAC12ENC; // DAC1
> do{}while(DAC12_0CTL & DAC12CALON == 1);
> do{}while(DAC12_1CTL & DAC12CALON == 1);
> DAC12_1DAT = 2048; // DAC1: ref 1V25 = 2V5/2
> //Setup Timer_A
> TACCTL1 = OUTMOD_3;
> TACCR1 = 2; // CCR1 PWM Duty Cycle
> TACCR0 = 4;
> //Setup Timer_B
> TBCCTL1 = OUTMOD_3;
> TBCCR1 = 1;
> TBCCR0 = 159;
>
> //Turn Off CPU forever
> _BIS_SR(LPM1_bits + GIE);
> }
> #pragma vector=ADC_VECTOR
> __interrupt void ADC12_ISR (void)
> {
> signal[index] = ADC12MEM0;
> TBCCR1 += 1; // Inc TB
> index += 1; // Inc vet ADC
> if(TBCCR1 == 160 && index ==
> 159) // Read finished, process....
> {
> /*Signal processing.....*/
> /*Send results....*/
> // Stop peripherals....
> TACTL &= ~MC_1; // stop timer A
> TBCTL &= ~MC_1; // stop timer B
> ADC12IE = 0x00; // Disable ADC
interrupts
> DMA0CTL &= ~DMAEN; // Disable DMA
> }
> }
> #pragma vector=USART0RX_VECTOR
> __interrupt void usart0_rx (void)
> {
> if(RXBUF0 == 65) // "A"
> {
> index = 0;
> DMA0SA = (int) Sin_tab;
> DMA0SZ = 32;
> DMA0CTL |= DMAEN; // Enable DMA
> DAC12_0CTL |= DAC12IFG; //
> Activate interrupt flag to start DAC
> DMA0CTL &= ~DMAIFG;
> ADC12IE = 0x01; // Enable ADC interrupts
> TBCCR1 = 1;
> TACTL |= TACLR;
> TBCTL |= TBCLR;
> // Start Timers
> TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
>
>
> }
> }
>

I fixed a typo in the code below, MC_1 wasn't
supposed to be in the first two lines .
Also I noticed on re-reading your code that you
already cleared Mode Control in the last ADC
interrupt, so my suggestion only really applies
to the pre-load to remove the offset. If I get a
chance, I'll load some code onto a board over the
next few days and have a look at it.

// Stop and re-synch timers
TACTL = TASSEL_2 | ID_0 | TACLR; // SMCLK, 0 to TACCR0, div clock = 1, stop
TBCTL = TBSSEL_2 | ID_0 | TBCLR; // SMCLK, 0 to TACCR0, div clock = 1, stop
// Start Timers
TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock = 1
TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock = 1

Hugh

At 11:37 AM 7/25/2008, you wrote:
I see that you clear the timers on receipt of the
"A", but you leave both of them running (TACLR
doesn't stop the timer) and the following TACTL
and TBCTL doesn't alter the count at that instant.

Perhaps change from this:
// Stop timers
TACTL |= TACLR;
TBCTL |= TBCLR;
// Start Timers
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1
TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1

To this:
// Stop and re-synch timers
TACTL = TASSEL_2 | MC_1 | ID_0 | TACLR; //
SMCLK, 0 to TACCR0, div clock = 1, stop
TBCTL = TBSSEL_2 | MC_1 | ID_0 | TBCLR; //
SMCLK, 0 to TACCR0, div clock = 1, stop
// Start Timers
TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock = 1
TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock = 1

The change from "+" to "|" is largely cosmetic,
but it better represents what you are trying to
achieve and can avoid some ripple errors when
incorrect definitions are used by mistake. With 2
timers, one is always started after the other so
to force them to have the same starting value you
would have to pre-load the earlier timer with a
value which increments to the required starting
value when the later timer starts. ie. how many
clock ticks are in the instruction "TBCTL="
above. If both cpu and timer are on 8MHz, then it
will be a few ticks; if the clock tick were much
slower than the cpu then there wouldn't be any. I
don't think you really care about that though, as
long as the relationship doesn't drift, but you
could pre-load TAR with (say) 4-2=2 after you
stop it but before you restart it. Look up the
assembly instruction which your compiler
generates then see how many clock cycles that requires.

The other option is to just use a single timer to
do both functions, but then of course you would
have to move the DAC CCR trigger forward each
interrupt as well as the ADC CCR trigger.

Also currently you require 160 complete DAC sine
wave cycles to acquire a complete ADC sine wave
cycle. You could reduce this drastically by
skipping ahead the appropriate minimum number of
sample points and sampling almost immediately,
instead of skipping just 1 point then waiting for
the next DAC sine wave cycle. That way you can
reduce the acquisition by an order of magnitude.

Also I assume you must calibrate the phase delay
for the ADC conversion time, along with the
front-end phase delay caused by any CR filter on
the DAC output and phase delay for extra
amplification on the ADC input. You can avoid
that calibration by making the reading
ratiometric. Use identical signal paths on both
DAC output after the filter and the measured
input, typically using a resistive divider on the
filtered output and a dual op-amp on the input
(assuming you are using an op-amp on the existing
input already). Then alternately measure the two
ADC inputs and the additional phase delay vanishes.

Hugh

At 07:14 AM 7/25/2008, you wrote:
Hi Hugh,

Thanks for your help.
The timer_B clock is 8MHz, so when I increment TBCCR1 in ADC isr the
TBR count is much more than TBCCR1+1, because the ADC isr is called
after the acquisition + conversion time that is 17 clock cicles of
5MHz ADC clock. I have sure that the timer_B and ADC are synchronized.
In the case of reseting timer_A and timer_B togheter, I do it in
each "A" receive. When the signal process finishes, I stop both
timers and initiates them again only when I receive an "A". Every
time that I receive "A", I have to start the measure process.
Since I stop the timers and peripherals after processing signal and I
clear and restart again the peripherals and timers only when "A"
receive, I think I don't need a timer isr to clear timer counters.
However, I implemented your suggestions, but didn't work.
I'm not understanding how to make the timers initialize always at the
same point...

--- In m..., Hugh Molesworth
wrote:
>
> Your first problem, I think, is that you move the
> next ADC sample point too soon. By this I mean
> that when TBCCR is hit an ADC conversion starts
> and completes controlled by the (typically) 5MHz
> ADC clock. On completion your ADC isr moves the
> synchronous sample point forward by 1 place:
> TBCCR1 += 1; // Inc TB
> However, this instruction may occur before TB has
> incremented again, which means potentially you
> have another ADC sample started before you are
> ready for it. Better to move that line of code to
> where you really want it to be, that is in the TB
> overflow interrupt when TB rolls over from 159 to 0.
>
> Your second problem is the loss of synch. Are you
> running this code just once, ie on receipt of an
> "A", or do you want it to run every time you
> receive an "A"? In that latter case, you need to
> re-synch the timers A & B on detection of the
> "A". Add this extra step either by just stopping
> and clearing the timers using TACLR and TBCLR, or
> by pre-loading the TAR and TBR counter registers
> to some other known value. Of course this is
> better done in the timer isr since the receipt of
> the "A" start character is asynchronous to the
> timer clocking, and therefore may occur as a tick
> is taking place giving potential instability in
> measurements. I suggest you set a flag in the rx
> isr which is checked in the timer isr, which when
> set stops and clears the timers and then restarts them.
>
> I removed the spurious "" characters in the
> code below for clarity. Not sure what they were ...
>
> Hugh
>
> At 06:08 AM 7/24/2008, you wrote:
> Hi,
> I want to measure the phase delay in an analog
> circuit applying a 50KHz sine wave generated in
> DAC (that access a table using DMA) and read this
> same signal with the ADC of the MSP430F156
> microcontroller. I want to reconstruct the sine
> wave readwith 160 points, so the ADCspeed
> doesn't support sample the 50KHz sine wave,
> however, I'm using a technique that I read 160
> sine wave cicles andget onesample of each
> cicle incrementing the point of sampling. I am
> using timer_A to generate clock for DACoutput
> the sine wave and Timer_B to start A/D
> conversionsin each point of the sine wave
> incrementing TBCCR1. I start the phase measure by
> software with RS232 communication, so when the
> firmware detects a start command from the
> software, it starts a measure generating the sine
> wave and, at the same time, reading it back.
> My problem is the start of both timers. I am
> starting timer_Bin the next line of timer_A
> start, butTimer_B does not start always in the
> same count of timer_A, and because that, the
> measure of phase delay between sine wave
> generated and sine wave read is not always the
> same. I'm not understanding what is happening.
> The most important part of the code follows below.
> Could somebodyhelp me?
> Thanks in advance,
> Ederson
> --------------------------------
--------------
>
> #include
> void main(void)
> {
> WDTCTL = WDTPW + WDTHOLD;
> /*Initialization of variables...*/
>
> BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
> do
> {
> IFG1 &= ~OFIFG;
> for (i = 0xFF; i > 0; i--);
> }
> while ((IFG1 & OFIFG));
> BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
> UCTL0 |= CHAR; // 8-bit character
> UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
> UBR00 = 0x41; // 8Mhz/9600
> UBR10 = 0x03; //
> UMCTL0 = 0x92; // no modulation
> ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
> UCTL0 &= ~SWRST; // Initialize USART state
machine
> IE1 |= URXIE0; // Enable USART0 RX
interrupt
>
> ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
> ADC12MCTL0 = SREF_1 +INCH_4 + EOS; //
VR+ = Vref+, VR- = AVss, A4 (P6.4)
> ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
> ADC12CTL0 |= ADC12ON + ENC;
>
>
> DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA
>
> // Setup DMA0
> DMA0SA = (int) Sin_tab;
> DMA0DA = DAC12_0DAT_;
> DMA0SZ = 32;
> DMA0CTL = DMADT_4 + DMASRCINCR_3; // + DMAIE;
> DMA0CTL |= DMAEN;
> //Setup DAC
> DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
> DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1 1V25 ref voltage
> DAC12_0CTL |= DAC12ENC; // DAC0
> DAC12_1CTL |= DAC12ENC; // DAC1
> do{}while(DAC12_0CTL & DAC12CALON == 1);
> do{}while(DAC12_1CTL & DAC12CALON == 1);
> DAC12_1DAT = 2048; // DAC1: ref 1V25 = 2V5/2
> //Setup Timer_A
> TACCTL1 = OUTMOD_3;
> TACCR1 = 2; // CCR1 PWM Duty Cycle
> TACCR0 = 4;
> //Setup Timer_B
> TBCCTL1 = OUTMOD_3;
> TBCCR1 = 1;
> TBCCR0 = 159;
>
> //Turn Off CPU forever
> _BIS_SR(LPM1_bits + GIE);
> }
> #pragma vector=ADC_VECTOR
> __interrupt void ADC12_ISR (void)
> {
> signal[index] = ADC12MEM0;
> TBCCR1 += 1; // Inc TB
> index += 1; // Inc vet ADC
> if(TBCCR1 == 160 && index == 159) // Read finished, process....
> {
> /*Signal processing.....*/
> /*Send results....*/
> // Stop peripherals....
> TACTL &= ~MC_1; // stop timer A
> TBCTL &= ~MC_1; // stop timer B
> ADC12IE = 0x00; // Disable ADC interrupts
> DMA0CTL &= ~DMAEN; // Disable DMA
> }
> }
> #pragma vector=USART0RX_VECTOR
> __interrupt void usart0_rx (void)
> {
> if(RXBUF0 == 65) // "A"
> {
> index = 0;
> DMA0SA = (int) Sin_tab;
> DMA0SZ = 32;
> DMA0CTL |= DMAEN; // Enable DMA
> DAC12_0CTL |= DAC12IFG; //
Activate interrupt flag to start DAC
> DMA0CTL &= ~DMAIFG;
> ADC12IE = 0x01; // Enable ADC interrupts
> TBCCR1 = 1;
> TACTL |= TACLR;
> TBCTL |= TBCLR;
> // Start Timers
> TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1
> TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div clock = 1
> }
> }

Thanks Hugh,

Now I'm still with the problem.
I verifyed that timer_B resets before the end of ADC isr. I thought
it was the problem, and I changed the code to get a sample waiting 2
cicles of the source signal to get other sample, by configuring
TBCCR0=319. It resolved the ADC isr problem, but didn't resolved the
main problem. I'm getting different measures of phase for readings of
the same analog circuit black box.
Now I don't have sure if the problem is the timers synchronization or
another.
However, I verifyed that the problem is in the first cycle sampled,
doesn't matter what I do with it after (signal processing...).
Sometimes my read get one phase delay, sometimes my read get another
phase delay.
Here is the big challenge: generate a 50KHz sine wave with DAC and
get it in ADC with the same phase delay always!

Ederson
--- In m..., Hugh Molesworth
wrote:
>
> I fixed a typo in the code below, MC_1 wasn't
> supposed to be in the first two lines .
> Also I noticed on re-reading your code that you
> already cleared Mode Control in the last ADC
> interrupt, so my suggestion only really applies
> to the pre-load to remove the offset. If I get a
> chance, I'll load some code onto a board over the
> next few days and have a look at it.
>
> // Stop and re-synch timers
> TACTL = TASSEL_2 | ID_0 | TACLR; // SMCLK, 0 to TACCR0, div
clock = 1, stop
> TBCTL = TBSSEL_2 | ID_0 | TBCLR; // SMCLK, 0 to TACCR0, div
clock = 1, stop
> // Start Timers
> TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
>
> Hugh
>
> At 11:37 AM 7/25/2008, you wrote:
> I see that you clear the timers on receipt of the
> "A", but you leave both of them running (TACLR
> doesn't stop the timer) and the following TACTL
> and TBCTL doesn't alter the count at that instant.
>
> Perhaps change from this:
> // Stop timers
> TACTL |= TACLR;
> TBCTL |= TBCLR;
> // Start Timers
> TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
>
> To this:
> // Stop and re-synch timers
> TACTL = TASSEL_2 | MC_1 | ID_0 | TACLR; //
> SMCLK, 0 to TACCR0, div clock = 1, stop
> TBCTL = TBSSEL_2 | MC_1 | ID_0 | TBCLR; //
> SMCLK, 0 to TACCR0, div clock = 1, stop
> // Start Timers
> TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock
= 1
> TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock
= 1
>
> The change from "+" to "|" is largely cosmetic,
> but it better represents what you are trying to
> achieve and can avoid some ripple errors when
> incorrect definitions are used by mistake. With 2
> timers, one is always started after the other so
> to force them to have the same starting value you
> would have to pre-load the earlier timer with a
> value which increments to the required starting
> value when the later timer starts. ie. how many
> clock ticks are in the instruction "TBCTL="
> above. If both cpu and timer are on 8MHz, then it
> will be a few ticks; if the clock tick were much
> slower than the cpu then there wouldn't be any. I
> don't think you really care about that though, as
> long as the relationship doesn't drift, but you
> could pre-load TAR with (say) 4-2=2 after you
> stop it but before you restart it. Look up the
> assembly instruction which your compiler
> generates then see how many clock cycles that requires.
>
> The other option is to just use a single timer to
> do both functions, but then of course you would
> have to move the DAC CCR trigger forward each
> interrupt as well as the ADC CCR trigger.
>
> Also currently you require 160 complete DAC sine
> wave cycles to acquire a complete ADC sine wave
> cycle. You could reduce this drastically by
> skipping ahead the appropriate minimum number of
> sample points and sampling almost immediately,
> instead of skipping just 1 point then waiting for
> the next DAC sine wave cycle. That way you can
> reduce the acquisition by an order of magnitude.
>
> Also I assume you must calibrate the phase delay
> for the ADC conversion time, along with the
> front-end phase delay caused by any CR filter on
> the DAC output and phase delay for extra
> amplification on the ADC input. You can avoid
> that calibration by making the reading
> ratiometric. Use identical signal paths on both
> DAC output after the filter and the measured
> input, typically using a resistive divider on the
> filtered output and a dual op-amp on the input
> (assuming you are using an op-amp on the existing
> input already). Then alternately measure the two
> ADC inputs and the additional phase delay vanishes.
>
> Hugh
>
> At 07:14 AM 7/25/2008, you wrote:
> Hi Hugh,
>
> Thanks for your help.
> The timer_B clock is 8MHz, so when I increment TBCCR1 in ADC isr the
> TBR count is much more than TBCCR1+1, because the ADC isr is called
> after the acquisition + conversion time that is 17 clock cicles of
> 5MHz ADC clock. I have sure that the timer_B and ADC are
synchronized.
> In the case of reseting timer_A and timer_B togheter, I do it in
> each "A" receive. When the signal process finishes, I stop both
> timers and initiates them again only when I receive an "A". Every
> time that I receive "A", I have to start the measure process.
> Since I stop the timers and peripherals after processing signal and
I
> clear and restart again the peripherals and timers only when "A"
> receive, I think I don't need a timer isr to clear timer counters.
> However, I implemented your suggestions, but didn't work.
> I'm not understanding how to make the timers initialize always at
the
> same point...
>
> --- In m..., Hugh Molesworth
> wrote:
> >
> > Your first problem, I think, is that you move the
> > next ADC sample point too soon. By this I mean
> > that when TBCCR is hit an ADC conversion starts
> > and completes controlled by the (typically) 5MHz
> > ADC clock. On completion your ADC isr moves the
> > synchronous sample point forward by 1 place:
> > TBCCR1 += 1; // Inc TB
> > However, this instruction may occur before TB has
> > incremented again, which means potentially you
> > have another ADC sample started before you are
> > ready for it. Better to move that line of code to
> > where you really want it to be, that is in the TB
> > overflow interrupt when TB rolls over from 159 to 0.
> >
> > Your second problem is the loss of synch. Are you
> > running this code just once, ie on receipt of an
> > "A", or do you want it to run every time you
> > receive an "A"? In that latter case, you need to
> > re-synch the timers A & B on detection of the
> > "A". Add this extra step either by just stopping
> > and clearing the timers using TACLR and TBCLR, or
> > by pre-loading the TAR and TBR counter registers
> > to some other known value. Of course this is
> > better done in the timer isr since the receipt of
> > the "A" start character is asynchronous to the
> > timer clocking, and therefore may occur as a tick
> > is taking place giving potential instability in
> > measurements. I suggest you set a flag in the rx
> > isr which is checked in the timer isr, which when
> > set stops and clears the timers and then restarts them.
> >
> > I removed the spurious "" characters in the
> > code below for clarity. Not sure what they were ...
> >
> > Hugh
> >
> > At 06:08 AM 7/24/2008, you wrote:
> > Hi,
> > I want to measure the phase delay in an analog
> > circuit applying a 50KHz sine wave generated in
> > DAC (that access a table using DMA) and read this
> > same signal with the ADC of the MSP430F156
> > microcontroller. I want to reconstruct the sine
> > wave read with 160 points, so the ADC speed
> > doesn't support sample the 50KHz sine wave,
> > however, I'm using a technique that I read 160
> > sine wave cicles and get one sample of each
> > cicle incrementing the point of sampling. I am
> > using timer_A to generate clock for DAC output
> > the sine wave and Timer_B to start A/D
> > conversions in each point of the sine wave
> > incrementing TBCCR1. I start the phase measure by
> > software with RS232 communication, so when the
> > firmware detects a start command from the
> > software, it starts a measure generating the sine
> > wave and, at the same time, reading it back.
> > My problem is the start of both timers. I am
> > starting timer_B in the next line of timer_A
> > start, but Timer_B does not start always in the
> > same count of timer_A, and because that, the
> > measure of phase delay between sine wave
> > generated and sine wave read is not always the
> > same. I'm not understanding what is happening.
> > The most important part of the code follows below.
> > Could somebody help me?
> > Thanks in advance,
> > Ederson
> > ----------------------------
----
> --------------
> >
> > #include
> > void main(void)
> > {
> > WDTCTL = WDTPW + WDTHOLD;
> > /*Initialization of variables...*/
> >
> > BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
> > do
> > {
> > IFG1 &= ~OFIFG;
> > for (i = 0xFF; i > 0; i--);
> > }
> > while ((IFG1 & OFIFG));
> > BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
> > UCTL0 |= CHAR; // 8-bit character
> > UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
> > UBR00 = 0x41; // 8Mhz/9600
> > UBR10 = 0x03; //
> > UMCTL0 = 0x92; // no modulation
> > ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
> > UCTL0 &= ~SWRST; // Initialize USART state
> machine
> > IE1 |= URXIE0; // Enable USART0 RX
> interrupt
> >
> > ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
> > ADC12MCTL0 = SREF_1 +INCH_4 + EOS; //
> VR+ = Vref+, VR- = AVss, A4 (P6.4)
> > ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
> ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
> > ADC12CTL0 |= ADC12ON + ENC;
> >
> >
> > DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA
> >
> > // Setup DMA0
> > DMA0SA = (int) Sin_tab;
> > DMA0DA = DAC12_0DAT_;
> > DMA0SZ = 32;
> > DMA0CTL = DMADT_4 + DMASRCINCR_3; // + DMAIE;
> > DMA0CTL |= DMAEN;
> > //Setup DAC
> > DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
> DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
> > DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1 1V25
ref voltage
> > DAC12_0CTL |= DAC12ENC; // DAC0
> > DAC12_1CTL |= DAC12ENC; // DAC1
> > do{}while(DAC12_0CTL & DAC12CALON == 1);
> > do{}while(DAC12_1CTL & DAC12CALON == 1);
> > DAC12_1DAT = 2048; // DAC1: ref 1V25 = 2V5/2
> > //Setup Timer_A
> > TACCTL1 = OUTMOD_3;
> > TACCR1 = 2; // CCR1 PWM Duty Cycle
> > TACCR0 = 4;
> > //Setup Timer_B
> > TBCCTL1 = OUTMOD_3;
> > TBCCR1 = 1;
> > TBCCR0 = 159;
> >
> > //Turn Off CPU forever
> > _BIS_SR(LPM1_bits + GIE);
> > }
> > #pragma vector=ADC_VECTOR
> > __interrupt void ADC12_ISR (void)
> > {
> > signal[index] = ADC12MEM0;
> > TBCCR1 += 1; // Inc TB
> > index += 1; // Inc vet ADC
> > if(TBCCR1 == 160 && index == 159) // Read finished,
process....
> > {
> > /*Signal processing.....*/
> > /*Send results....*/
> > // Stop peripherals....
> > TACTL &= ~MC_1; // stop timer A
> > TBCTL &= ~MC_1; // stop timer B
> > ADC12IE = 0x00; // Disable ADC interrupts
> > DMA0CTL &= ~DMAEN; // Disable DMA
> > }
> > }
> > #pragma vector=USART0RX_VECTOR
> > __interrupt void usart0_rx (void)
> > {
> > if(RXBUF0 == 65) // "A"
> > {
> > index = 0;
> > DMA0SA = (int) Sin_tab;
> > DMA0SZ = 32;
> > DMA0CTL |= DMAEN; // Enable DMA
> > DAC12_0CTL |= DAC12IFG; //
> Activate interrupt flag to start DAC
> > DMA0CTL &= ~DMAIFG;
> > ADC12IE = 0x01; // Enable ADC interrupts
> > TBCCR1 = 1;
> > TACTL |= TACLR;
> > TBCTL |= TBCLR;
> > // Start Timers
> > TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> > TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> > }
> > }
>

A couple of things I noticed while loading up a
board, though I got sidetracked before I got
further with it. One is that you post-increment
the counters then test, so you are one cycle
short of the 160 samples you are looking for, I
think, since you read for index = 0 to 158 but
you never actually read index=159 since you reset
the counters at that point. That by itself might explain your issue.

The other thought I had is to do away with
messing about with CCR += 1 and instead just set
the B counter effective length to 161 instead of
160 8MHz cycles. Since the sine wave has an
effective length of 160 8MHz cycles, that will
cause the sample point to shift by 1 cycle each full since wave cycle.

Also I notice that with interrupt overhead and
time to process, the 8MHz '149 is not going to be
an order of magnitude faster by sampling
comb-like more than 1 sample per full sine cycle
as I suggested; you might get a factor of x2 or
x3 faster but no more so it probably isn't worth
trying. I was thinking of the nice 25MHz '5438 I
was playing with which is a lot faster.

Ok, last point. The 5MHz ADC clock is
asynchronous to the 8MHz DAC clock, so there will
be jitter in the sampled ADC reading. better to
also use the 8MHz clock for the ADC. Also the
sample window for the ADC is relatively long
compared with the 20uSec/32 DAC step; you can
shorten it by going to a single 8MHz clock width
sample (set SHP=0) but then I think you might run
foul of some ADC errata. Have to try it and see.

You have an interesting problem; I was looking at
something similar for 32kHz and 50kHz
ultrasonics. I'll try and look at it further.

Hugh

At 01:42 PM 7/30/2008, you wrote:
Thanks Hugh,

Now I'm still with the problem.
I verifyed that timer_B resets before the end of ADC isr. I thought
it was the problem, and I changed the code to get a sample waiting 2
cicles of the source signal to get other sample, by configuring
TBCCR0=319. It resolved the ADC isr problem, but didn't resolved the
main problem. I'm getting different measures of phase for readings of
the same analog circuit black box.
Now I don't have sure if the problem is the timers synchronization or
another.
However, I verifyed that the problem is in the first cycle sampled,
doesn't matter what I do with it after (signal processing...).
Sometimes my read get one phase delay, sometimes my read get another
phase delay.
Here is the big challenge: generate a 50KHz sine wave with DAC and
get it in ADC with the same phase delay always!

Ederson
--- In m..., Hugh Molesworth
wrote:
>
> I fixed a typo in the code below, MC_1 wasn't
> supposed to be in the first two lines .
> Also I noticed on re-reading your code that you
> already cleared Mode Control in the last ADC
> interrupt, so my suggestion only really applies
> to the pre-load to remove the offset. If I get a
> chance, I'll load some code onto a board over the
> next few days and have a look at it.
>
> // Stop and re-synch timers
> TACTL = TASSEL_2 | ID_0 | TACLR; // SMCLK, 0 to TACCR0, div
clock = 1, stop
> TBCTL = TBSSEL_2 | ID_0 | TBCLR; // SMCLK, 0 to TACCR0, div
clock = 1, stop
> // Start Timers
> TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
>
> Hugh
>
> At 11:37 AM 7/25/2008, you wrote:
> I see that you clear the timers on receipt of the
> "A", but you leave both of them running (TACLR
> doesn't stop the timer) and the following TACTL
> and TBCTL doesn't alter the count at that instant.
>
> Perhaps change from this:
> // Stop timers
> TACTL |= TACLR;
> TBCTL |= TBCLR;
> // Start Timers
> TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
>
> To this:
> // Stop and re-synch timers
> TACTL = TASSEL_2 | MC_1 | ID_0 | TACLR; //
> SMCLK, 0 to TACCR0, div clock = 1, stop
> TBCTL = TBSSEL_2 | MC_1 | ID_0 | TBCLR; //
> SMCLK, 0 to TACCR0, div clock = 1, stop
> // Start Timers
> TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock
= 1
> TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div clock
= 1
>
> The change from "+" to "|" is largely cosmetic,
> but it better represents what you are trying to
> achieve and can avoid some ripple errors when
> incorrect definitions are used by mistake. With 2
> timers, one is always started after the other so
> to force them to have the same starting value you
> would have to pre-load the earlier timer with a
> value which increments to the required starting
> value when the later timer starts. ie. how many
> clock ticks are in the instruction "TBCTL="
> above. If both cpu and timer are on 8MHz, then it
> will be a few ticks; if the clock tick were much
> slower than the cpu then there wouldn't be any. I
> don't think you really care about that though, as
> long as the relationship doesn't drift, but you
> could pre-load TAR with (say) 4-2=2 after you
> stop it but before you restart it. Look up the
> assembly instruction which your compiler
> generates then see how many clock cycles that requires.
>
> The other option is to just use a single timer to
> do both functions, but then of course you would
> have to move the DAC CCR trigger forward each
> interrupt as well as the ADC CCR trigger.
>
> Also currently you require 160 complete DAC sine
> wave cycles to acquire a complete ADC sine wave
> cycle. You could reduce this drastically by
> skipping ahead the appropriate minimum number of
> sample points and sampling almost immediately,
> instead of skipping just 1 point then waiting for
> the next DAC sine wave cycle. That way you can
> reduce the acquisition by an order of magnitude.
>
> Also I assume you must calibrate the phase delay
> for the ADC conversion time, along with the
> front-end phase delay caused by any CR filter on
> the DAC output and phase delay for extra
> amplification on the ADC input. You can avoid
> that calibration by making the reading
> ratiometric. Use identical signal paths on both
> DAC output after the filter and the measured
> input, typically using a resistive divider on the
> filtered output and a dual op-amp on the input
> (assuming you are using an op-amp on the existing
> input already). Then alternately measure the two
> ADC inputs and the additional phase delay vanishes.
>
> Hugh
>
> At 07:14 AM 7/25/2008, you wrote:
> Hi Hugh,
>
> Thanks for your help.
> The timer_B clock is 8MHz, so when I increment TBCCR1 in ADC isr the
> TBR count is much more than TBCCR1+1, because the ADC isr is called
> after the acquisition + conversion time that is 17 clock cicles of
> 5MHz ADC clock. I have sure that the timer_B and ADC are
synchronized.
> In the case of reseting timer_A and timer_B togheter, I do it in
> each "A" receive. When the signal process finishes, I stop both
> timers and initiates them again only when I receive an "A". Every
> time that I receive "A", I have to start the measure process.
> Since I stop the timers and peripherals after processing signal and
I
> clear and restart again the peripherals and timers only when "A"
> receive, I think I don't need a timer isr to clear timer counters.
> However, I implemented your suggestions, but didn't work.
> I'm not understanding how to make the timers initialize always at
the
> same point...
>
> --- In m..., Hugh Molesworth
> wrote:
> >
> > Your first problem, I think, is that you move the
> > next ADC sample point too soon. By this I mean
> > that when TBCCR is hit an ADC conversion starts
> > and completes controlled by the (typically) 5MHz
> > ADC clock. On completion your ADC isr moves the
> > synchronous sample point forward by 1 place:
> > TBCCR1 += 1; // Inc TB
> > However, this instruction may occur before TB has
> > incremented again, which means potentially you
> > have another ADC sample started before you are
> > ready for it. Better to move that line of code to
> > where you really want it to be, that is in the TB
> > overflow interrupt when TB rolls over from 159 to 0.
> >
> > Your second problem is the loss of synch. Are you
> > running this code just once, ie on receipt of an
> > "A", or do you want it to run every time you
> > receive an "A"? In that latter case, you need to
> > re-synch the timers A & B on detection of the
> > "A". Add this extra step either by just stopping
> > and clearing the timers using TACLR and TBCLR, or
> > by pre-loading the TAR and TBR counter registers
> > to some other known value. Of course this is
> > better done in the timer isr since the receipt of
> > the "A" start character is asynchronous to the
> > timer clocking, and therefore may occur as a tick
> > is taking place giving potential instability in
> > measurements. I suggest you set a flag in the rx
> > isr which is checked in the timer isr, which when
> > set stops and clears the timers and then restarts them.
> >
> > I removed the spurious "" characters in the
> > code below for clarity. Not sure what they were ...
> >
> > Hugh
> >
> > At 06:08 AM 7/24/2008, you wrote:
> > Hi,
> > I want to measure the phase delay in an analog
> > circuit applying a 50KHz sine wave generated in
> > DAC (that access a table using DMA) and read this
> > same signal with the ADC of the MSP430F156
> > microcontroller. I want to reconstruct the sine
> > wave read with 160 points, so the ADC speed
> > doesn't support sample the 50KHz sine wave,
> > however, I'm using a technique that I read 160
> > sine wave cicles and get one sample of each
> > cicle incrementing the point of sampling. I am
> > using timer_A to generate clock for DAC output
> > the sine wave and Timer_B to start A/D
> > conversions in each point of the sine wave
> > incrementing TBCCR1. I start the phase measure by
> > software with RS232 communication, so when the
> > firmware detects a start command from the
> > software, it starts a measure generating the sine
> > wave and, at the same time, reading it back.
> > My problem is the start of both timers. I am
> > starting timer_B in the next line of timer_A
> > start, but Timer_B does not start always in the
> > same count of timer_A, and because that, the
> > measure of phase delay between sine wave
> > generated and sine wave read is not always the
> > same. I'm not understanding what is happening.
> > The most important part of the code follows below.
> > Could somebody help me?
> > Thanks in advance,
> > Ederson
> > ----------------------------
----
> --------------
> >
> > #include
> > void main(void)
> > {
> > WDTCTL = WDTPW + WDTHOLD;
> > /*Initialization of variables...*/
> >
> > BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
> > do
> > {
> > IFG1 &= ~OFIFG;
> > for (i = 0xFF; i > 0; i--);
> > }
> > while ((IFG1 & OFIFG));
> > BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
> > UCTL0 |= CHAR; // 8-bit character
> > UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
> > UBR00 = 0x41; // 8Mhz/9600
> > UBR10 = 0x03; //
> > UMCTL0 = 0x92; // no modulation
> > ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
> > UCTL0 &= ~SWRST; // Initialize USART state
> machine
> > IE1 |= URXIE0; // Enable USART0 RX
> interrupt
> >
> > ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
> > ADC12MCTL0 = SREF_1 +INCH_4 + EOS; //
> VR+ = Vref+, VR- = AVss, A4 (P6.4)
> > ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
> ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
> > ADC12CTL0 |= ADC12ON + ENC;
> >
> >
> > DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA
> >
> > // Setup DMA0
> > DMA0SA = (int) Sin_tab;
> > DMA0DA = DAC12_0DAT_;
> > DMA0SZ = 32;
> > DMA0CTL = DMADT_4 + DMASRCINCR_3; // + DMAIE;
> > DMA0CTL |= DMAEN;
> > //Setup DAC
> > DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
> DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
> > DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1 1V25
ref voltage
> > DAC12_0CTL |= DAC12ENC; // DAC0
> > DAC12_1CTL |= DAC12ENC; // DAC1
> > do{}while(DAC12_0CTL & DAC12CALON == 1);
> > do{}while(DAC12_1CTL & DAC12CALON == 1);
> > DAC12_1DAT = 2048; // DAC1: ref 1V25 = 2V5/2
> > //Setup Timer_A
> > TACCTL1 = OUTMOD_3;
> > TACCR1 = 2; // CCR1 PWM Duty Cycle
> > TACCR0 = 4;
> > //Setup Timer_B
> > TBCCTL1 = OUTMOD_3;
> > TBCCR1 = 1;
> > TBCCR0 = 159;
> >
> > //Turn Off CPU forever
> > _BIS_SR(LPM1_bits + GIE);
> > }
> > #pragma vector=ADC_VECTOR
> > __interrupt void ADC12_ISR (void)
> > {
> > signal[index] = ADC12MEM0;
> > TBCCR1 += 1; // Inc TB
> > index += 1; // Inc vet ADC
> > if(TBCCR1 == 160 && index == 159) // Read finished,
process....
> > {
> > /*Signal processing.....*/
> > /*Send results....*/
> > // Stop peripherals....
> > TACTL &= ~MC_1; // stop timer A
> > TBCTL &= ~MC_1; // stop timer B
> > ADC12IE = 0x00; // Disable ADC interrupts
> > DMA0CTL &= ~DMAEN; // Disable DMA
> > }
> > }
> > #pragma vector=USART0RX_VECTOR
> > __interrupt void usart0_rx (void)
> > {
> > if(RXBUF0 == 65) // "A"
> > {
> > index = 0;
> > DMA0SA = (int) Sin_tab;
> > DMA0SZ = 32;
> > DMA0CTL |= DMAEN; // Enable DMA
> > DAC12_0CTL |= DAC12IFG; //
> Activate interrupt flag to start DAC
> > DMA0CTL &= ~DMAIFG;
> > ADC12IE = 0x01; // Enable ADC interrupts
> > TBCCR1 = 1;
> > TACTL |= TACLR;
> > TBCTL |= TBCLR;
> > // Start Timers
> > TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> > TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
clock = 1
> > }
> > }
>

Hello Hugh,

Your suggestion about configurate timer lenght with one more point to
shift signal sample was very good. And about index, you have sure, I
was missing one sample. I verifyed the other things, but the
different measures is still happen.
Now I saw that in the fist measure, for the first "A" serial receive,
after microcontroller reset, the result is always the same, but in
new "A" receive, without microcontroler reset, the following measures
get different values.
One solution is reset microcontroller after any measure, but is not a
good procedure.
I tried to read ADC samples by using the other DMA channel, but when
the both DMAs (DMA0 to DAC sine wave generation triggered by timer_A
and DMA1 to ADC 160 point read triggered by timer_B) are working
toghether, the timers get crazy and this solution doesn't work.
So now the main question is: Why the measure restart process have a
behavior different than the first measure? May be a trash in some
register? I verifyed the reset of all registers involved in the start
of a new measure. But the result is the same only in the first
measure... May be a problem with MSP430?

Ederson
--- In m..., Hugh Molesworth
wrote:
>
> A couple of things I noticed while loading up a
> board, though I got sidetracked before I got
> further with it. One is that you post-increment
> the counters then test, so you are one cycle
> short of the 160 samples you are looking for, I
> think, since you read for index = 0 to 158 but
> you never actually read index=159 since you reset
> the counters at that point. That by itself might explain your issue.
>
> The other thought I had is to do away with
> messing about with CCR += 1 and instead just set
> the B counter effective length to 161 instead of
> 160 8MHz cycles. Since the sine wave has an
> effective length of 160 8MHz cycles, that will
> cause the sample point to shift by 1 cycle each full since wave
cycle.
>
> Also I notice that with interrupt overhead and
> time to process, the 8MHz '149 is not going to be
> an order of magnitude faster by sampling
> comb-like more than 1 sample per full sine cycle
> as I suggested; you might get a factor of x2 or
> x3 faster but no more so it probably isn't worth
> trying. I was thinking of the nice 25MHz '5438 I
> was playing with which is a lot faster.
>
> Ok, last point. The 5MHz ADC clock is
> asynchronous to the 8MHz DAC clock, so there will
> be jitter in the sampled ADC reading. better to
> also use the 8MHz clock for the ADC. Also the
> sample window for the ADC is relatively long
> compared with the 20uSec/32 DAC step; you can
> shorten it by going to a single 8MHz clock width
> sample (set SHP=0) but then I think you might run
> foul of some ADC errata. Have to try it and see.
>
> You have an interesting problem; I was looking at
> something similar for 32kHz and 50kHz
> ultrasonics. I'll try and look at it further.
>
> Hugh
>
> At 01:42 PM 7/30/2008, you wrote:
> Thanks Hugh,
>
> Now I'm still with the problem.
> I verifyed that timer_B resets before the end of ADC isr. I thought
> it was the problem, and I changed the code to get a sample waiting 2
> cicles of the source signal to get other sample, by configuring
> TBCCR0=319. It resolved the ADC isr problem, but didn't resolved the
> main problem. I'm getting different measures of phase for readings
of
> the same analog circuit black box.
> Now I don't have sure if the problem is the timers synchronization
or
> another.
> However, I verifyed that the problem is in the first cycle sampled,
> doesn't matter what I do with it after (signal processing...).
> Sometimes my read get one phase delay, sometimes my read get another
> phase delay.
> Here is the big challenge: generate a 50KHz sine wave with DAC and
> get it in ADC with the same phase delay always!
>
> Ederson
>
>
> --- In m..., Hugh Molesworth
> wrote:
> >
> > I fixed a typo in the code below, MC_1 wasn't
> > supposed to be in the first two lines .
> > Also I noticed on re-reading your code that you
> > already cleared Mode Control in the last ADC
> > interrupt, so my suggestion only really applies
> > to the pre-load to remove the offset. If I get a
> > chance, I'll load some code onto a board over the
> > next few days and have a look at it.
> >
> > // Stop and re-synch timers
> > TACTL = TASSEL_2 | ID_0 | TACLR; // SMCLK, 0 to TACCR0, div
> clock = 1, stop
> > TBCTL = TBSSEL_2 | ID_0 | TBCLR; // SMCLK, 0 to TACCR0, div
> clock = 1, stop
> > // Start Timers
> > TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> > TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> >
> > Hugh
> >
> > At 11:37 AM 7/25/2008, you wrote:
> > I see that you clear the timers on receipt of the
> > "A", but you leave both of them running (TACLR
> > doesn't stop the timer) and the following TACTL
> > and TBCTL doesn't alter the count at that instant.
> >
> > Perhaps change from this:
> > // Stop timers
> > TACTL |= TACLR;
> > TBCTL |= TBCLR;
> > // Start Timers
> > TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> > TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> >
> > To this:
> > // Stop and re-synch timers
> > TACTL = TASSEL_2 | MC_1 | ID_0 | TACLR; //
> > SMCLK, 0 to TACCR0, div clock = 1, stop
> > TBCTL = TBSSEL_2 | MC_1 | ID_0 | TBCLR; //
> > SMCLK, 0 to TACCR0, div clock = 1, stop
> > // Start Timers
> > TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock
> = 1
> > TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock
> = 1
> >
> > The change from "+" to "|" is largely cosmetic,
> > but it better represents what you are trying to
> > achieve and can avoid some ripple errors when
> > incorrect definitions are used by mistake. With 2
> > timers, one is always started after the other so
> > to force them to have the same starting value you
> > would have to pre-load the earlier timer with a
> > value which increments to the required starting
> > value when the later timer starts. ie. how many
> > clock ticks are in the instruction "TBCTL="
> > above. If both cpu and timer are on 8MHz, then it
> > will be a few ticks; if the clock tick were much
> > slower than the cpu then there wouldn't be any. I
> > don't think you really care about that though, as
> > long as the relationship doesn't drift, but you
> > could pre-load TAR with (say) 4-2=2 after you
> > stop it but before you restart it. Look up the
> > assembly instruction which your compiler
> > generates then see how many clock cycles that requires.
> >
> > The other option is to just use a single timer to
> > do both functions, but then of course you would
> > have to move the DAC CCR trigger forward each
> > interrupt as well as the ADC CCR trigger.
> >
> > Also currently you require 160 complete DAC sine
> > wave cycles to acquire a complete ADC sine wave
> > cycle. You could reduce this drastically by
> > skipping ahead the appropriate minimum number of
> > sample points and sampling almost immediately,
> > instead of skipping just 1 point then waiting for
> > the next DAC sine wave cycle. That way you can
> > reduce the acquisition by an order of magnitude.
> >
> > Also I assume you must calibrate the phase delay
> > for the ADC conversion time, along with the
> > front-end phase delay caused by any CR filter on
> > the DAC output and phase delay for extra
> > amplification on the ADC input. You can avoid
> > that calibration by making the reading
> > ratiometric. Use identical signal paths on both
> > DAC output after the filter and the measured
> > input, typically using a resistive divider on the
> > filtered output and a dual op-amp on the input
> > (assuming you are using an op-amp on the existing
> > input already). Then alternately measure the two
> > ADC inputs and the additional phase delay vanishes.
> >
> > Hugh
> >
> > At 07:14 AM 7/25/2008, you wrote:
> > Hi Hugh,
> >
> > Thanks for your help.
> > The timer_B clock is 8MHz, so when I increment TBCCR1 in ADC isr
the
> > TBR count is much more than TBCCR1+1, because the ADC isr is
called
> > after the acquisition + conversion time that is 17 clock cicles
of
> > 5MHz ADC clock. I have sure that the timer_B and ADC are
> synchronized.
> > In the case of reseting timer_A and timer_B togheter, I do it in
> > each "A" receive. When the signal process finishes, I stop both
> > timers and initiates them again only when I receive an "A". Every
> > time that I receive "A", I have to start the measure process.
> > Since I stop the timers and peripherals after processing signal
and
> I
> > clear and restart again the peripherals and timers only when "A"
> > receive, I think I don't need a timer isr to clear timer
counters.
> > However, I implemented your suggestions, but didn't work.
> > I'm not understanding how to make the timers initialize always at
> the
> > same point...
> >
> > --- In m..., Hugh Molesworth
> > wrote:
> > >
> > > Your first problem, I think, is that you move the
> > > next ADC sample point too soon. By this I mean
> > > that when TBCCR is hit an ADC conversion starts
> > > and completes controlled by the (typically) 5MHz
> > > ADC clock. On completion your ADC isr moves the
> > > synchronous sample point forward by 1 place:
> > > TBCCR1 += 1; // Inc TB
> > > However, this instruction may occur before TB has
> > > incremented again, which means potentially you
> > > have another ADC sample started before you are
> > > ready for it. Better to move that line of code to
> > > where you really want it to be, that is in the TB
> > > overflow interrupt when TB rolls over from 159 to 0.
> > >
> > > Your second problem is the loss of synch. Are you
> > > running this code just once, ie on receipt of an
> > > "A", or do you want it to run every time you
> > > receive an "A"? In that latter case, you need to
> > > re-synch the timers A & B on detection of the
> > > "A". Add this extra step either by just stopping
> > > and clearing the timers using TACLR and TBCLR, or
> > > by pre-loading the TAR and TBR counter registers
> > > to some other known value. Of course this is
> > > better done in the timer isr since the receipt of
> > > the "A" start character is asynchronous to the
> > > timer clocking, and therefore may occur as a tick
> > > is taking place giving potential instability in
> > > measurements. I suggest you set a flag in the rx
> > > isr which is checked in the timer isr, which when
> > > set stops and clears the timers and then restarts them.
> > >
> > > I removed the spurious "" characters in the
> > > code below for clarity. Not sure what they were ...
> > >
> > > Hugh
> > >
> > > At 06:08 AM 7/24/2008, you wrote:
> > > Hi,
> > > I want to measure the phase delay in an analog
> > > circuit applying a 50KHz sine wave generated in
> > > DAC (that access a table using DMA) and read this
> > > same signal with the ADC of the MSP430F156
> > > microcontroller. I want to reconstruct the sine
> > > wave read with 160 points, so the ADC speed
> > > doesn't support sample the 50KHz sine wave,
> > > however, I'm using a technique that I read 160
> > > sine wave cicles and get one sample of each
> > > cicle incrementing the point of sampling. I am
> > > using timer_A to generate clock for DAC output
> > > the sine wave and Timer_B to start A/D
> > > conversions in each point of the sine wave
> > > incrementing TBCCR1. I start the phase measure by
> > > software with RS232 communication, so when the
> > > firmware detects a start command from the
> > > software, it starts a measure generating the sine
> > > wave and, at the same time, reading it back.
> > > My problem is the start of both timers. I am
> > > starting timer_B in the next line of timer_A
> > > start, but Timer_B does not start always in the
> > > same count of timer_A, and because that, the
> > > measure of phase delay between sine wave
> > > generated and sine wave read is not always the
> > > same. I'm not understanding what is happening.
> > > The most important part of the code follows below.
> > > Could somebody help me?
> > > Thanks in advance,
> > > Ederson
> > > -------------------------
---
> ----
> > --------------
> > >
> > > #include
> > > void main(void)
> > > {
> > > WDTCTL = WDTPW + WDTHOLD;
> > > /*Initialization of variables...*/
> > >
> > > BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
> > > do
> > > {
> > > IFG1 &= ~OFIFG;
> > > for (i = 0xFF; i > 0; i--);
> > > }
> > > while ((IFG1 & OFIFG));
> > > BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
> > > UCTL0 |= CHAR; // 8-bit character
> > > UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
> > > UBR00 = 0x41; // 8Mhz/9600
> > > UBR10 = 0x03; //
> > > UMCTL0 = 0x92; // no modulation
> > > ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
> > > UCTL0 &= ~SWRST; // Initialize USART
state
> > machine
> > > IE1 |= URXIE0; // Enable USART0 RX
> > interrupt
> > >
> > > ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
> > > ADC12MCTL0 = SREF_1 +INCH_4 + EOS; //
> > VR+ = Vref+, VR- = AVss, A4 (P6.4)
> > > ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
> > ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
> > > ADC12CTL0 |= ADC12ON + ENC;
> > >
> > >
> > > DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA
> > >
> > > // Setup DMA0
> > > DMA0SA = (int) Sin_tab;
> > > DMA0DA = DAC12_0DAT_;
> > > DMA0SZ = 32;
> > > DMA0CTL = DMADT_4 + DMASRCINCR_3; // + DMAIE;
> > > DMA0CTL |= DMAEN;
> > > //Setup DAC
> > > DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
> > DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
> > > DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1
1V25
> ref voltage
> > > DAC12_0CTL |= DAC12ENC; // DAC0
> > > DAC12_1CTL |= DAC12ENC; // DAC1
> > > do{}while(DAC12_0CTL & DAC12CALON == 1);
> > > do{}while(DAC12_1CTL & DAC12CALON == 1);
> > > DAC12_1DAT = 2048; // DAC1: ref 1V25 =
2V5/2
> > > //Setup Timer_A
> > > TACCTL1 = OUTMOD_3;
> > > TACCR1 = 2; // CCR1 PWM Duty Cycle
> > > TACCR0 = 4;
> > > //Setup Timer_B
> > > TBCCTL1 = OUTMOD_3;
> > > TBCCR1 = 1;
> > > TBCCR0 = 159;
> > >
> > > //Turn Off CPU forever
> > > _BIS_SR(LPM1_bits + GIE);
> > > }
> > > #pragma vector=ADC_VECTOR
> > > __interrupt void ADC12_ISR (void)
> > > {
> > > signal[index] = ADC12MEM0;
> > > TBCCR1 += 1; // Inc TB
> > > index += 1; // Inc vet ADC
> > > if(TBCCR1 == 160 && index == 159) // Read finished,
> process....
> > > {
> > > /*Signal processing.....*/
> > > /*Send results....*/
> > > // Stop peripherals....
> > > TACTL &= ~MC_1; // stop timer A
> > > TBCTL &= ~MC_1; // stop timer B
> > > ADC12IE = 0x00; // Disable ADC
interrupts
> > > DMA0CTL &= ~DMAEN; // Disable DMA
> > > }
> > > }
> > > #pragma vector=USART0RX_VECTOR
> > > __interrupt void usart0_rx (void)
> > > {
> > > if(RXBUF0 == 65) // "A"
> > > {
> > > index = 0;
> > > DMA0SA = (int) Sin_tab;
> > > DMA0SZ = 32;
> > > DMA0CTL |= DMAEN; // Enable DMA
> > > DAC12_0CTL |= DAC12IFG; //
> > Activate interrupt flag to start DAC
> > > DMA0CTL &= ~DMAIFG;
> > > ADC12IE = 0x01; // Enable ADC interrupts
> > > TBCCR1 = 1;
> > > TACTL |= TACLR;
> > > TBCTL |= TBCLR;
> > > // Start Timers
> > > TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0,
div
> clock = 1
> > > TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0,
div
> clock = 1
> > > }
> > > }
>
Hi Ederson

You just provided an important clue, I think. Try
slowing down your clock from the full 8MHz to
(say) 2MHz by applying the /4 option in both
timers, and see if that makes a difference; I
suspect your interrupts are running out of time
so that you miss some ticks, which of course will
mess up your samples. Do you have interrupts from
other sources doing anything, by the way?

I looked at the sync of the two timers, and I
don't have a problem. However, I'm not running
your exact code, though as I mentioned if I can
find time I will try it. You can check the timer
outputs on port pins, and make it easier by
reducing the B timer length from 160 to something
more easily observable on a 'scope, such as 10
(ie. only take 10 ADC samples per full 160-pulse
DMA sine cycle). Pulse a port pin at the start
and end of your interrupt, one port pin dedicated
to each type of interrupt. Display the analogue
waveform with these timer outputs and pulses and
it might be easier to see what is happening. On
the '149 ADC12 the 160 ADC samples are not really
meaningful anyway, since the ADC sample is too
long, unless you can get the single clock sample
mode to work correctly (set SHP=0). Your code
currently averages over a sample time of 4+ clock
cycles. I suppose you could look at that as a moving average.

Hugh

At 05:58 AM 8/1/2008, you wrote:
Hello Hugh,

Your suggestion about configurate timer lenght with one more point to
shift signal sample was very good. And about index, you have sure, I
was missing one sample. I verifyed the other things, but the
different measures is still happen.
Now I saw that in the fist measure, for the first "A" serial receive,
after microcontroller reset, the result is always the same, but in
new "A" receive, without microcontroler reset, the following measures
get different values.
One solution is reset microcontroller after any measure, but is not a
good procedure.
I tried to read ADC samples by using the other DMA channel, but when
the both DMAs (DMA0 to DAC sine wave generation triggered by timer_A
and DMA1 to ADC 160 point read triggered by timer_B) are working
toghether, the timers get crazy and this solution doesn't work.
So now the main question is: Why the measure restart process have a
behavior different than the first measure? May be a trash in some
register? I verifyed the reset of all registers involved in the start
of a new measure. But the result is the same only in the first
measure... May be a problem with MSP430?

Ederson
--- In m..., Hugh Molesworth
wrote:
>
> A couple of things I noticed while loading up a
> board, though I got sidetracked before I got
> further with it. One is that you post-increment
> the counters then test, so you are one cycle
> short of the 160 samples you are looking for, I
> think, since you read for index = 0 to 158 but
> you never actually read index=159 since you reset
> the counters at that point. That by itself might explain your issue.
>
> The other thought I had is to do away with
> messing about with CCR += 1 and instead just set
> the B counter effective length to 161 instead of
> 160 8MHz cycles. Since the sine wave has an
> effective length of 160 8MHz cycles, that will
> cause the sample point to shift by 1 cycle each full since wave
cycle.
>
> Also I notice that with interrupt overhead and
> time to process, the 8MHz '149 is not going to be
> an order of magnitude faster by sampling
> comb-like more than 1 sample per full sine cycle
> as I suggested; you might get a factor of x2 or
> x3 faster but no more so it probably isn't worth
> trying. I was thinking of the nice 25MHz '5438 I
> was playing with which is a lot faster.
>
> Ok, last point. The 5MHz ADC clock is
> asynchronous to the 8MHz DAC clock, so there will
> be jitter in the sampled ADC reading. better to
> also use the 8MHz clock for the ADC. Also the
> sample window for the ADC is relatively long
> compared with the 20uSec/32 DAC step; you can
> shorten it by going to a single 8MHz clock width
> sample (set SHP=0) but then I think you might run
> foul of some ADC errata. Have to try it and see.
>
> You have an interesting problem; I was looking at
> something similar for 32kHz and 50kHz
> ultrasonics. I'll try and look at it further.
>
> Hugh
>
> At 01:42 PM 7/30/2008, you wrote:
> Thanks Hugh,
>
> Now I'm still with the problem.
> I verifyed that timer_B resets before the end of ADC isr. I thought
> it was the problem, and I changed the code to get a sample waiting 2
> cicles of the source signal to get other sample, by configuring
> TBCCR0=319. It resolved the ADC isr problem, but didn't resolved the
> main problem. I'm getting different measures of phase for readings
of
> the same analog circuit black box.
> Now I don't have sure if the problem is the timers synchronization
or
> another.
> However, I verifyed that the problem is in the first cycle sampled,
> doesn't matter what I do with it after (signal processing...).
> Sometimes my read get one phase delay, sometimes my read get another
> phase delay.
> Here is the big challenge: generate a 50KHz sine wave with DAC and
> get it in ADC with the same phase delay always!
>
> Ederson
>
>
> --- In m..., Hugh Molesworth
> wrote:
> >
> > I fixed a typo in the code below, MC_1 wasn't
> > supposed to be in the first two lines .
> > Also I noticed on re-reading your code that you
> > already cleared Mode Control in the last ADC
> > interrupt, so my suggestion only really applies
> > to the pre-load to remove the offset. If I get a
> > chance, I'll load some code onto a board over the
> > next few days and have a look at it.
> >
> > // Stop and re-synch timers
> > TACTL = TASSEL_2 | ID_0 | TACLR; // SMCLK, 0 to TACCR0, div
> clock = 1, stop
> > TBCTL = TBSSEL_2 | ID_0 | TBCLR; // SMCLK, 0 to TACCR0, div
> clock = 1, stop
> > // Start Timers
> > TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> > TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> >
> > Hugh
> >
> > At 11:37 AM 7/25/2008, you wrote:
> > I see that you clear the timers on receipt of the
> > "A", but you leave both of them running (TACLR
> > doesn't stop the timer) and the following TACTL
> > and TBCTL doesn't alter the count at that instant.
> >
> > Perhaps change from this:
> > // Stop timers
> > TACTL |= TACLR;
> > TBCTL |= TBCLR;
> > // Start Timers
> > TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> > TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0, div
> clock = 1
> >
> > To this:
> > // Stop and re-synch timers
> > TACTL = TASSEL_2 | MC_1 | ID_0 | TACLR; //
> > SMCLK, 0 to TACCR0, div clock = 1, stop
> > TBCTL = TBSSEL_2 | MC_1 | ID_0 | TBCLR; //
> > SMCLK, 0 to TACCR0, div clock = 1, stop
> > // Start Timers
> > TACTL = TASSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock
> = 1
> > TBCTL = TBSSEL_2 | MC_1 | ID_0; // SMCLK, 0 to TACCR0, div
clock
> = 1
> >
> > The change from "+" to "|" is largely cosmetic,
> > but it better represents what you are trying to
> > achieve and can avoid some ripple errors when
> > incorrect definitions are used by mistake. With 2
> > timers, one is always started after the other so
> > to force them to have the same starting value you
> > would have to pre-load the earlier timer with a
> > value which increments to the required starting
> > value when the later timer starts. ie. how many
> > clock ticks are in the instruction "TBCTL="
> > above. If both cpu and timer are on 8MHz, then it
> > will be a few ticks; if the clock tick were much
> > slower than the cpu then there wouldn't be any. I
> > don't think you really care about that though, as
> > long as the relationship doesn't drift, but you
> > could pre-load TAR with (say) 4-2=2 after you
> > stop it but before you restart it. Look up the
> > assembly instruction which your compiler
> > generates then see how many clock cycles that requires.
> >
> > The other option is to just use a single timer to
> > do both functions, but then of course you would
> > have to move the DAC CCR trigger forward each
> > interrupt as well as the ADC CCR trigger.
> >
> > Also currently you require 160 complete DAC sine
> > wave cycles to acquire a complete ADC sine wave
> > cycle. You could reduce this drastically by
> > skipping ahead the appropriate minimum number of
> > sample points and sampling almost immediately,
> > instead of skipping just 1 point then waiting for
> > the next DAC sine wave cycle. That way you can
> > reduce the acquisition by an order of magnitude.
> >
> > Also I assume you must calibrate the phase delay
> > for the ADC conversion time, along with the
> > front-end phase delay caused by any CR filter on
> > the DAC output and phase delay for extra
> > amplification on the ADC input. You can avoid
> > that calibration by making the reading
> > ratiometric. Use identical signal paths on both
> > DAC output after the filter and the measured
> > input, typically using a resistive divider on the
> > filtered output and a dual op-amp on the input
> > (assuming you are using an op-amp on the existing
> > input already). Then alternately measure the two
> > ADC inputs and the additional phase delay vanishes.
> >
> > Hugh
> >
> > At 07:14 AM 7/25/2008, you wrote:
> > Hi Hugh,
> >
> > Thanks for your help.
> > The timer_B clock is 8MHz, so when I increment TBCCR1 in ADC isr
the
> > TBR count is much more than TBCCR1+1, because the ADC isr is
called
> > after the acquisition + conversion time that is 17 clock cicles
of
> > 5MHz ADC clock. I have sure that the timer_B and ADC are
> synchronized.
> > In the case of reseting timer_A and timer_B togheter, I do it in
> > each "A" receive. When the signal process finishes, I stop both
> > timers and initiates them again only when I receive an "A". Every
> > time that I receive "A", I have to start the measure process.
> > Since I stop the timers and peripherals after processing signal
and
> I
> > clear and restart again the peripherals and timers only when "A"
> > receive, I think I don't need a timer isr to clear timer
counters.
> > However, I implemented your suggestions, but didn't work.
> > I'm not understanding how to make the timers initialize always at
> the
> > same point...
> >
> > --- In m..., Hugh Molesworth
> > wrote:
> > >
> > > Your first problem, I think, is that you move the
> > > next ADC sample point too soon. By this I mean
> > > that when TBCCR is hit an ADC conversion starts
> > > and completes controlled by the (typically) 5MHz
> > > ADC clock. On completion your ADC isr moves the
> > > synchronous sample point forward by 1 place:
> > > TBCCR1 += 1; // Inc TB
> > > However, this instruction may occur before TB has
> > > incremented again, which means potentially you
> > > have another ADC sample started before you are
> > > ready for it. Better to move that line of code to
> > > where you really want it to be, that is in the TB
> > > overflow interrupt when TB rolls over from 159 to 0.
> > >
> > > Your second problem is the loss of synch. Are you
> > > running this code just once, ie on receipt of an
> > > "A", or do you want it to run every time you
> > > receive an "A"? In that latter case, you need to
> > > re-synch the timers A & B on detection of the
> > > "A". Add this extra step either by just stopping
> > > and clearing the timers using TACLR and TBCLR, or
> > > by pre-loading the TAR and TBR counter registers
> > > to some other known value. Of course this is
> > > better done in the timer isr since the receipt of
> > > the "A" start character is asynchronous to the
> > > timer clocking, and therefore may occur as a tick
> > > is taking place giving potential instability in
> > > measurements. I suggest you set a flag in the rx
> > > isr which is checked in the timer isr, which when
> > > set stops and clears the timers and then restarts them.
> > >
> > > I removed the spurious "" characters in the
> > > code below for clarity. Not sure what they were ...
> > >
> > > Hugh
> > >
> > > At 06:08 AM 7/24/2008, you wrote:
> > > Hi,
> > > I want to measure the phase delay in an analog
> > > circuit applying a 50KHz sine wave generated in
> > > DAC (that access a table using DMA) and read this
> > > same signal with the ADC of the MSP430F156
> > > microcontroller. I want to reconstruct the sine
> > > wave read with 160 points, so the ADC speed
> > > doesn't support sample the 50KHz sine wave,
> > > however, I'm using a technique that I read 160
> > > sine wave cicles and get one sample of each
> > > cicle incrementing the point of sampling. I am
> > > using timer_A to generate clock for DAC output
> > > the sine wave and Timer_B to start A/D
> > > conversions in each point of the sine wave
> > > incrementing TBCCR1. I start the phase measure by
> > > software with RS232 communication, so when the
> > > firmware detects a start command from the
> > > software, it starts a measure generating the sine
> > > wave and, at the same time, reading it back.
> > > My problem is the start of both timers. I am
> > > starting timer_B in the next line of timer_A
> > > start, but Timer_B does not start always in the
> > > same count of timer_A, and because that, the
> > > measure of phase delay between sine wave
> > > generated and sine wave read is not always the
> > > same. I'm not understanding what is happening.
> > > The most important part of the code follows below.
> > > Could somebody help me?
> > > Thanks in advance,
> > > Ederson
> > > -------------------------
---
> ----
> > --------------
> > >
> > > #include
> > > void main(void)
> > > {
> > > WDTCTL = WDTPW + WDTHOLD;
> > > /*Initialization of variables...*/
> > >
> > > BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL
> > > do
> > > {
> > > IFG1 &= ~OFIFG;
> > > for (i = 0xFF; i > 0; i--);
> > > }
> > > while ((IFG1 & OFIFG));
> > > BCSCTL2 |= SELM_2 + SELS; // MCLK= XT2
> > > UCTL0 |= CHAR; // 8-bit character
> > > UTCTL0 |= SSEL0 + SSEL1; // UCLK = SMCLK
> > > UBR00 = 0x41; // 8Mhz/9600
> > > UBR10 = 0x03; //
> > > UMCTL0 = 0x92; // no modulation
> > > ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
> > > UCTL0 &= ~SWRST; // Initialize USART
state
> > machine
> > > IE1 |= URXIE0; // Enable USART0 RX
> > interrupt
> > >
> > > ADC12CTL0 = SHT0_0 + REF2_5V + REFON;
> > > ADC12MCTL0 = SREF_1 +INCH_4 + EOS; //
> > VR+ = Vref+, VR- = AVss, A4 (P6.4)
> > > ADC12CTL1 = SHS_3 + CONSEQ_2 + SHP +
> > ADC12DIV_0 + ADC12SSEL_0; // S&H TB1OUT, div = 1, ADC12OSC
> > > ADC12CTL0 |= ADC12ON + ENC;
> > >
> > >
> > > DMACTL0 = DMA0TSEL_5; // DAC12IFG trigger DMA
> > >
> > > // Setup DMA0
> > > DMA0SA = (int) Sin_tab;
> > > DMA0DA = DAC12_0DAT_;
> > > DMA0SZ = 32;
> > > DMA0CTL = DMADT_4 + DMASRCINCR_3; // + DMAIE;
> > > DMA0CTL |= DMAEN;
> > > //Setup DAC
> > > DAC12_0CTL = DAC12LSEL_2 + DAC12IR +
> > DAC12AMP_7 + DAC12CALON; // DAC0 50KHz wave
> > > DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12CALON; // DAC1
1V25
> ref voltage
> > > DAC12_0CTL |= DAC12ENC; // DAC0
> > > DAC12_1CTL |= DAC12ENC; // DAC1
> > > do{}while(DAC12_0CTL & DAC12CALON == 1);
> > > do{}while(DAC12_1CTL & DAC12CALON == 1);
> > > DAC12_1DAT = 2048; // DAC1: ref 1V25 =
2V5/2
> > > //Setup Timer_A
> > > TACCTL1 = OUTMOD_3;
> > > TACCR1 = 2; // CCR1 PWM Duty Cycle
> > > TACCR0 = 4;
> > > //Setup Timer_B
> > > TBCCTL1 = OUTMOD_3;
> > > TBCCR1 = 1;
> > > TBCCR0 = 159;
> > >
> > > //Turn Off CPU forever
> > > _BIS_SR(LPM1_bits + GIE);
> > > }
> > > #pragma vector=ADC_VECTOR
> > > __interrupt void ADC12_ISR (void)
> > > {
> > > signal[index] = ADC12MEM0;
> > > TBCCR1 += 1; // Inc TB
> > > index += 1; // Inc vet ADC
> > > if(TBCCR1 == 160 && index == 159) // Read finished,
> process....
> > > {
> > > /*Signal processing.....*/
> > > /*Send results....*/
> > > // Stop peripherals....
> > > TACTL &= ~MC_1; // stop timer A
> > > TBCTL &= ~MC_1; // stop timer B
> > > ADC12IE = 0x00; // Disable ADC
interrupts
> > > DMA0CTL &= ~DMAEN; // Disable DMA
> > > }
> > > }
> > > #pragma vector=USART0RX_VECTOR
> > > __interrupt void usart0_rx (void)
> > > {
> > > if(RXBUF0 == 65) // "A"
> > > {
> > > index = 0;
> > > DMA0SA = (int) Sin_tab;
> > > DMA0SZ = 32;
> > > DMA0CTL |= DMAEN; // Enable DMA
> > > DAC12_0CTL |= DAC12IFG; //
> > Activate interrupt flag to start DAC
> > > DMA0CTL &= ~DMAIFG;
> > > ADC12IE = 0x01; // Enable ADC interrupts
> > > TBCCR1 = 1;
> > > TACTL |= TACLR;
> > > TBCTL |= TBCLR;
> > > // Start Timers
> > > TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0,
div
> clock = 1
> > > TBCTL = TBSSEL_2 + MC_1 + ID_0; // SMCLK, 0 to TACCR0,
div
> clock = 1
> > > }
> > > }
> >
>

Hi Hugh,

Thanks again for your very good suggestions. You will don't believe
in where was the problem: I must initialyze timers before the
DAC+DMA!!! Other thing is that I have to get one sample in each 2
sine wave cicles, because 20us is not enought for ADC
sample+conversion+isr.
And now I resolved the syncronization problem.
Thank you very much for dedicate some of your time to help me.

Best regards,

Ederson
--- In m..., Hugh Molesworth
wrote:
>
> Hi Ederson
>
> You just provided an important clue, I think. Try
> slowing down your clock from the full 8MHz to
> (say) 2MHz by applying the /4 option in both
> timers, and see if that makes a difference; I
> suspect your interrupts are running out of time
> so that you miss some ticks, which of course will
> mess up your samples. Do you have interrupts from
> other sources doing anything, by the way?
>
> I looked at the sync of the two timers, and I
> don't have a problem. However, I'm not running
> your exact code, though as I mentioned if I can
> find time I will try it. You can check the timer
> outputs on port pins, and make it easier by
> reducing the B timer length from 160 to something
> more easily observable on a 'scope, such as 10
> (ie. only take 10 ADC samples per full 160-pulse
> DMA sine cycle). Pulse a port pin at the start
> and end of your interrupt, one port pin dedicated
> to each type of interrupt. Display the analogue
> waveform with these timer outputs and pulses and
> it might be easier to see what is happening. On
> the '149 ADC12 the 160 ADC samples are not really
> meaningful anyway, since the ADC sample is too
> long, unless you can get the single clock sample
> mode to work correctly (set SHP=0). Your code
> currently averages over a sample time of 4+ clock
> cycles. I suppose you could look at that as a moving average.
>
> Hugh
>