Pages: [1]   Go Down
Author Topic: Problem with generation of TTL Pulses with defined length using timers  (Read 1519 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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!


* Clipboard01.jpg (482.18 KB, 1633x551 - viewed 13 times.)
« Last Edit: January 17, 2014, 02:00:22 pm by MarinaK » Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 598
Posts: 33337
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Canada
Offline Offline
Sr. Member
****
Karma: 13
Posts: 401
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Electricity is really just organized lightning - George Carlin

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
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 smiley
Logged

Pages: [1]   Go Up
Jump to: