Go Down

Topic: Timer Interrupts on Due (Read 228292 times) previous topic - next topic

ss13

hi
i want to design a timer with arduino mega 2560
this time must have a restore point and Measure every 10 millisecond and display this time on the lcd
i have a lot of problem
the first problem is for reset point
i cant active the reset point and show this on the lcd
please help me
this is my email
fziaee93@yahoo.com
please send your proposed about my project to my email
thanks alot

youthreewire

How to set an external clock signals for the interrupt? I am using a codec chip with the Due where the codec shield sends an external clock out.I need to sync the external clock from the codec with the due. I have the follow code for timer but I dont think it does that.
'
Code: [Select]
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
        pmc_set_writeprotect(false);
        pmc_enable_periph_clk((uint32_t)irq);
        TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
        uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
        TC_SetRA(tc, channel, rc/2); //50% high, 50% low
        TC_SetRC(tc, channel, rc);
        TC_Start(tc, channel);
        tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
        tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
        NVIC_EnableIRQ(irq);
}

sayrol

Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);
        digitalWrite(13, l = !l);
}

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
        pmc_set_writeprotect(false);
        pmc_enable_periph_clk((uint32_t)irq);
        TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
        uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
        TC_SetRA(tc, channel, rc/2); //50% high, 50% low
        TC_SetRC(tc, channel, rc);
        TC_Start(tc, channel);
        tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
        tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
        NVIC_EnableIRQ(irq);
}

void setup(){
        pinMode(13,OUTPUT);
        startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:
ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12

Someone can help me please. I wanna know where do you get these functions from : pmc_set_writeprotect(false);
TC_SetRA(tc, channel, rc/2); //50% high, 50% low
TC_SetRC(tc, channel, rc);
TC_GetStatus(TC1, 0);
Because I searched in datasheet ATMEL SAM3X (1459 pages), and i never found anything about that.

Wurstnase

Quote
Someone can help me please. I wanna know where do you get these functions from : pmc_set_writeprotect(false);
TC_SetRA(tc, channel, rc/2); //50% high, 50% low
TC_SetRC(tc, channel, rc);
TC_GetStatus(TC1, 0);
Because I searched in datasheet ATMEL SAM3X (1459 pages), and i never found anything about that.
Because it's libsam and CMSIS.

RustyBody

Thanks for the great info but I would really be interested to know how to include the Atmel Studio project (solution) directory structure in an Arduino project, which includes CMSIS and more. It's to big to "flatten" and i really don't want to have to do what others have done in this thread - dig down to the binary register values. Since macros are still in use, I assume there is a file somewhere with the #define statements (pointing to register addresses) but where?

FYI, Atmel Studio is available for free from Atmel. It only runs in Windoze, however and you will need a JEDEC or some other interface in order to program Arduino's with Atmel code. The debugger is really handy, though. (I use a SAM-ICE hadware debugger/interface.)

Thanks,
Rusty

steadyState


Hi,

If I understand correctly, I can trigger an interrupt through the TC_IER register on RA, RB and RC compare, then on counter overflow, and others. Is the ISR called always this TCn_Handler()?

Does anybody know about a way to call different ISRs upon different trigger cases?


Thanks,
steady

ard_newbie


All enabled interrupts of  TC counter TCx will trigger TCx_Handler().


Inside the call back Handler, you:
1/ Read and save the status register, which saves  status bits and clears immediately bits so the interrupt can be triggered again

2/ you test in the saved status variable which bit is up (e.g. RA compare )

steadyState

2/ you test in the saved status variable which bit is up (e.g. RA compare )
Then, when you read the answer, suddenly all is so obvious... ;-)

Thank you very much, that makes it clear.

terryz

Here is another resource on using Due timers.


http://2manyprojects.net/timer-interrupts


Steenoluf

Steen Oluf Karlsen here! I would like to use timer interrupts on an Arduino Due to run a sampling function that is calling analogRead. The samples should be taken with the sampling time Ts between them. I try to deduct all your advice here. I see the last posting is from nov 2012 - so it's more than 7 years that have passed!

ard_newbie


There are numerous example sketches provided in the DUE sub forum for ADC conversions triggered by a timer counter or a PWM Event Line.


Another one:

Code: [Select]

/**********************************************************************************************/
/*   ADC conversions of 1 analog input triggered at 3 KHz by TC0 channel 2 TIOA2 pulse        */
/**********************************************************************************************/

volatile boolean AnalogConversion;
volatile uint16_t Result;

void setup()
{

  pinMode(LED_BUILTIN, OUTPUT);
  adc_setup();
  tc_setup();
}

void loop()
{

  if (AnalogConversion)
  {
    //Do smething with Result
    AnalogConversion = false;
  }
}

/*************  Configure ADC function  *******************/
void adc_setup() {

  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                    // ADC power on

  ADC->ADC_CR = ADC_CR_SWRST;                           // Reset ADC
  ADC->ADC_MR |=  ADC_MR_TRGEN_EN                       // Hardware trigger select
                  | ADC_MR_TRANSFER(2)
                  | ADC_MR_PRESCAL(1)
                  | ADC_MR_TRGSEL_ADC_TRIG3;            // Trigger by TIOA2

  //ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequency > 500 KHz

  ADC->ADC_IER = ADC_IER_EOC7;            // Interrupt on End Of Conversions channel 7

  ADC->ADC_CHER = ADC_CHER_CH7;           // Enable Channels 7 = A0

  NVIC_EnableIRQ((IRQn_Type)ADC_IRQn);    // Enable ADC interrupt
}

void ADC_Handler () {

  static uint32_t Count;

  Result = ADC->ADC_CDR[7];
  AnalogConversion = true;

  if (Count++ == 3000)
  {
    PIOB->PIO_ODSR ^= PIO_ODSR_P27;
    Count = 0;
  }
}

/*************  Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2  ************/
void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                      // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK3  // MCK/32, clk on rising edge
                              | TC_CMR_WAVE               // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match

  TC0->TC_CHANNEL[2].TC_RC = 875;  //<*********************  Frequency = (Mck/32)/TC_RC  Hz = 3000 Hz
  TC0->TC_CHANNEL[2].TC_RA = 400;  //<********************   Any Duty cycle in between 1 and 874

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;// Software trigger TC2 counter and enable
}



Steenoluf

Ok thanks, Ard_newbie. I will look into this. I have implemented an analogRead(0) inside a for-loop that runs SIGLEN times. I have used delay_microseconds(Ts - runtime); // Obtain SampleTime (Ts) as specified

It actually has worked quite well- but I got the feeling I could do much better if I used timed interrupts.
That the whole thing would work more precise.

I understand that calling the analogRead() function often takes too long time.
That if I can go directly to the relevant registers it will speed up things tremendously.

Steenoluf

Ok so I can choose my own sampling frequency! I read here: 84MHz/(32*875) = 3 kHz

  TC0->TC_CHANNEL[2].TC_RC = 875;  //<**********  Frequency = (Mck/32)/TC_RC  Hz = 3000 Hz

I still need to understand the real time flow of the sampling, though. I see a parameter reset when
3000 samples is reached:

  if (Count++ == 3000)
  {
    PIOB->PIO_ODSR ^= PIO_ODSR_P27;
    Count = 0;
  }

I will need to transfer each Result sample value to an input buffer of a given length, say 4096 samples.
I understand that with the timer interrupt the writing of the buffer will be continuous -
so the input buffer would be "circular" and at any given point in time it would be possible to read the latest 4096 samples. I am afraid I do not understand the use of the "bitwise XOR" "^=" statement !?
Thanks in advance!

ard_newbie


The blinking LED is an "optionnal" feature, only for debugging (1 Hz blinking LED).

Search on your favorite search engine how works bitwise XOR.

Steenoluf

I have your code running now, ard_newbie. I have a scope on D13. I see the 1Hz  square wave.

I tried to change the count limit to 1050 and the sampling frequency to 4096 samples/s which I use in my project. As expected I get an up-time on D13 of 1050/4096 = 256ms.

I have another frequency band however where I would like to use f_sampl = 40960 samples/s.

This gives the clock divider calculation TC_RC  =(84E+6)/(32*40960) = 64 (approx)
Now: This gives no activity on D13 at all. Is there maybe a lower limit to TC_RC ?




Go Up