Go Down

Topic: Problem with generation of TTL Pulses with defined length using timers (Read 2124 times) previous topic - next topic

MarinaK

I'm new to microcontroller programming and to arduino, so please excuse me if I'm asking obvious things.

I'm trying to generate a TLL pulse with a predefined length after the ADC has detected the defined threshold. So far succeeded to detect the threshold (I used this post as an example http://forum.arduino.cc/index.php?topic=205096.0).
For my application it is important to minimize the jitter between the detection of the threshold and the generation of the pulse. So I can't use arduionos functions.

My idea was to use a second timer to define the length of the pulse. In the datasheet I've found that I can restart the timer after a number of counts defined in the TC_RC register, which should raise a flag in the TC_SRx in the CPCS byte.
So I definde the value of RC to correspond to a 75 ms long pulse but the CPCS bit appears to never be set. The code compiles and I don't get any errors.
I've inserted the whole code here:
Code: [Select]
void setup()
{
 Serial.begin (115200) ; // was for debugging
 adc_setup () ;         // setup ADC
 
 pmc_enable_periph_clk (TC_INTERFACE_ID + 0*3+0) ;  // clock the TC0 channel 0 (timer for the adc)
 pmc_enable_periph_clk (TC_INTERFACE_ID + 0*3+1) ;  // clock the TC0 channel 1 (timer for the pulse length)


 TcChannel * t = &(TC0->TC_CHANNEL)[0] ;    // pointer to TC0 registers for its channel 0
 t->TC_CCR = TC_CCR_CLKDIS |TC_CCR_CLKEN;  // disable internal clocking while setup regs
 t->TC_IDR = 0xFFFFFFFF ;     // disable interrupts
 t->TC_SR ;                   // read int status reg to clear pending
 t->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 |   // use TCLK1 (prescale by 2, = 42MHz)
             TC_CMR_WAVE |                  // waveform mode
             TC_CMR_WAVSEL_UP_RC |          // count-up PWM using RC as threshold
             TC_CMR_EEVT_XC0 |     // Set external events from XC0 (this setup TIOB as output)
             TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
             TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR ;
 
 t->TC_RC =  875 ;     // counter resets on RC, so sets period in terms of 42MHz clockTC
 t->TC_RA =  440 ;     // roughly square wave
 t->TC_CMR = (t->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET ;  // set clear and set from RA and RC compares
 
 t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ;  // re-enable local clocking and switch to hardware trigger source.

 TcChannel * t1 = &(TC0->TC_CHANNEL)[1] ;    // pointer to TC0 registers for its channel 1
 t1->TC_CCR = TC_CCR_CLKDIS |TC_CCR_CLKEN;  // disable internal clocking while setup regs
 t1->TC_IER |= 0x10 ;     // enable RC interrupt
 //t1->TC_SR ;                   // read int status reg to clear pending
 t1->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 |   // use TCLK1 (prescale by 2, = 42MHz)
             TC_CMR_WAVE |                  // waveform mode
             TC_CMR_WAVSEL_UP_RC |          // count-up PWM using RC as threshold
             TC_CMR_EEVT_XC0 |     // Set external events from XC0 (this setup TIOB as output)
             TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
             TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR ;
 
 t1->TC_RC =  300000000 ;     // counter resets on RC, so sets period in terms of 13,88 Hz clock (for laser trigger)
 t1->TC_RA =  440 ;     // roughly square wave
 t1->TC_CMR = (t1->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET ;  // set clear and set from RA and RC compares
 
 t1->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ;  // re-enable local clocking and switch to hardware trigger source.
 
 setup_pio_TIOA0 () ;  // drive Arduino pin 2 at 48kHz to bring clock out
 pio_out_setup();
}

void setup_pio_TIOA0 ()  // Configure Ard pin 2 as output from TC0 channel A (copy of trigger event)
{
 PIOB->PIO_PDR = PIO_PB25B_TIOA0 ;  // disable PIO control
 PIOB->PIO_IDR = PIO_PB25B_TIOA0 ;   // disable PIO interrupts
 PIOB->PIO_ABSR |= PIO_PB25B_TIOA0 ;  // switch to B peripheral

}

void pio_out_setup()//set pin 23 as output
{
   pmc_enable_periph_clk(ID_PIOA);
   PIOA->PIO_MDDR = PIO_MDDR_P14;
   PIOA->PIO_CODR = PIO_CODR_P14;
   PIOA->PIO_OWER = PIO_OWER_P14;
   PIOA->PIO_OER = PIO_OER_P14;
   PIOA->PIO_PER = PIO_PER_P14;
}

void adc_setup ()
{
 NVIC_EnableIRQ (ADC_IRQn) ;   // enable ADC interrupt vector
 ADC->ADC_IDR = 0xFFFFFFFF ;   // disable interrupts
 ADC->ADC_IER = 0x80 ;         // enable AD7 End-Of-Conv interrupt (Arduino pin A0)
 ADC->ADC_CHDR = 0xFFFF ;      // disable all channels
 ADC->ADC_CHER = 0x80 ;        // enable just A0
 ADC->ADC_CGR = 0x15555555 ;   // All gains set to x1
 ADC->ADC_COR = 0x00000000 ;   // All offsets off
 
 ADC->ADC_MR = (ADC->ADC_MR & 0xFFFFFFF0) | (1 << 1) | ADC_MR_TRGEN ;  // 1 = trig source TIO from TC0
 ADC->ADC_EMR = 0x201; // generate an event when the data is higher than the threashold, raise flag after one event, compare all channels
 ADC->ADC_CWR = ADC_CWR_HIGHTHRES(2000); //set threshold to 1.5 (12 Bit resolution)
}

void ADC_Handler (void)
{
 if (ADC->ADC_ISR & ADC_ISR_COMPE)   // ensure there was COMPE flag raised
 {
  PIOA->PIO_SODR=PIO_SODR_P14;
  //Serial.println(TC0->TC_CHANNEL[1].TC_SR,BIN);
 
  while(TC0->TC_CHANNEL[1].TC_SR&0x10==0)
  {//v= TC0->TC_CHANNEL[1].TC_CV;
 
  }
   PIOA->PIO_CODR= PIO_CODR_P14;
 }  
}

void loop()
{
}


on the scope I see the following result (see the attached image)
the yellow signal is intup of the ADC channel and the blue is the TTL pulse. it is 70 ns wide and I want 75ms.

I'll appreciate if anybody has an idea how to get the timer going or any other suggestions how to generate such a pulse.

Thanks alot for your help!

Grumpy_Mike

Quote
For my application it is important to minimize the jitter between the detection of the threshold and the generation of the pulse. So I can't use arduionos functions.

In which case do not use an arduino but a bit of simple hardware.
Feed your signal into a voltage comparator like an LM339 with a pot setting the threshold.
Then use the output to trigger a monostable like a 74LS123 or one made with an NE555.

dlloyd

Re: 37.7.11 TC Channel Mode Register: Waveform Mode (datasheet)
In your setup code, try setting CPCSTOP bit to 1 so that the counter clock will stop when it reaches RC.

MarinaK

Thanks for the quick answers!
I've finally got the result I wanted. However it's a little workaround since the CPCS flag was never raised in the TC_RS register in my case.
Here the pieces of code I've modified:
Code: [Select]
t1->TC_CMR|= TC_CMR_CPCSTOP;       //counter clock is stopped when counter reaches RC
  t1->TC_RC =  3000000 ;     // counter resets on RC
  t1->TC_RA =  1500000 ;     // roughly square wave


and
Code: [Select]

void ADC_Handler (void)
{
  long v;
  if (ADC->ADC_ISR & ADC_ISR_COMPE)   // ensure there was COMPE flag raised
  {
   PIOA->PIO_SODR=PIO_SODR_P14;      // set leven of PIN 23 to HIGH
   ADC->ADC_CHDR = 0xFFFF;           // switsch off all ADC CHANNELs
   TC0->TC_CHANNEL[1].TC_CCR=TC_CCR_SWTRG;  // reset timer t1
   v=TC0->TC_CHANNEL[1].TC_CV;       // read out timer value
   while(v<3000000)                  // wait ~70 ms according to timer settings
   {v=TC0->TC_CHANNEL[1].TC_CV;}
   PIOA->PIO_CODR= PIO_CODR_P14;  // set leven of PIN 23 to LOW
   ADC->ADC_CHER = 0x80 ;        // enable just A0
  }


The jitter is currently in the oder of 1us... I'll try out if it's tollerable in my setup . Otherwise I'll look into the comparator option... thanks for the suggestion :)

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy