I have a sketch for testing timers on Due. Timer8 generates an interrupt when RA is loaded. The interrupt handler is
void TC8_Handler() // ISR TC8 (TC2 Channel 2)
{
if (TC2->TC_CHANNEL[2].TC_SR & TC_SR_LDRAS) // Check for RA load condition
{
introk = 1;
frequ = TC2->TC_CHANNEL[2].TC_RA;
}
}
In loop variable freq is displayed on the Serial Monitor:
void loop() {
// put your main code here, to run repeatedly:
if (introk) { // in case of interrupts
introk=0;
Serial.print("f=");Serial.println(frequ);
}
}
This works well.
But when I comment the if statement within interrupt handler there are'nt any interrupts at all.
Here is the complete sketch for measuring frequency on a Due.
Explanations at the beginning of code in English in short:
" Timer7 generates a 1 sec gate signal on TIOA7 output (D3). This output shall be connected with TIOA8 input (D11) of Timer8. Timer8 is counting the frequency on TCLK8 input (D30). The signal on TIOA7 is triggering the counter in Timer8. Falling edge of this signal loads RA which then contains frequency in Hz."
#include <Arduino.h>
#define PROCTIME (15000) // time between measurements
volatile uint8_t introk=0;
volatile uint32_t frequ=0;
void setup() {
Serial.begin(19200);
/* Timer7 erzeugt ein 1 sec Gatesignal auf TIOA7, das mit dem
Eingang TIOA8 von Timer8 verbunden wird.
Timer8 zählt die Takte der Eingangsfrequenz an TCLK8 waehrend
der Gatezeit von 1 sec.
Der Counter von Timer8 wird vom TIOA8-Eingang so gesteuert, dass
er jeweils mit der positiven Flanke getriggert wird (zuruecksetzen
und starten). Mit der negativen Flanke an TIOA8 wird der Counterwert
nach Register A uebernommen und ein Interrupt ausgeloest, der den
Inhalt von Register A in die Variable frequ speichert.
TIOA7 auf D3/PC28/peripheral B, TIOA8 auf D11/PD7/peripheral B,
TCLK8 auf D30/PD9/peripheral B.
*/
// Clocks fuer TC7 und TC8 aktivieren:
PMC->PMC_PCER1 |= PMC_PCER1_PID34 | PMC_PCER1_PID35; // clock Timer Counter Channel 7 & 8
// Pin fuer TIOA7 konfigurieren:
PIOC->PIO_ABSR |= PIO_ABSR_P28; // Switch the multiplexer on pin PC28 to peripheral B (TIOA7)
PIOC->PIO_PDR |= PIO_PDR_P28; // Disable the GPIO on pin PC28
// Pins fuer TCLK8 und TIOA8 konfigurieren:
PIOD->PIO_ABSR |= PIO_ABSR_P7; // Switch the multiplexer on pin PD7 to peripheral B (TIOA8)
PIOD->PIO_PDR |= PIO_PDR_P7; // Disable the GPIO on TIOA8
PIOD->PIO_ABSR |= PIO_ABSR_P9; // Switch the multiplexer on pin PD9 to peripheral B (TCLK8)
PIOD->PIO_PDR |= PIO_PDR_P9; // Disable the GPIO on pin PD9
// TC7 (Modul 2, Channel 1) auf Wave Mode :
TC2->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK4 | // MCK/128 = 656250 Hz
TC_CMR_WAVSEL_UP_RC | // cnt up, RC compare triggers
TC_CMR_WAVE | // set wave mode
TC_CMR_ACPA_SET | // RA compare sets TIOA to high
TC_CMR_ACPC_CLEAR | // RC compare sets TIOA to low
TC_CMR_ASWTRG_CLEAR; // SW trigger sets TIOA to low
TC2->TC_CHANNEL[1].TC_RA = PROCTIME;
TC2->TC_CHANNEL[1].TC_RC = 656250 + PROCTIME;
// TC8 (Modul 2, Channel 2) auf Capture Mode:
TC2->TC_BMR = TC_BMR_TC2XC2S_TCLK2; // TCLK2 of TC-Modul2 to XC2
TC2->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_XC2 | // clock TCLK8 on XC2
TC_CMR_ETRGEDG_RISING | // rising edge on TIOA triggers counter
TC_CMR_ABETRG | // TIOA is external trigger
TC_CMR_LDRA_FALLING ; // RA load on falling edge on TIOA
TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_CLKEN; // enable clock
NVIC_EnableIRQ(TC8_IRQn); // Connect TC8 to Nested Vector Interrupt Controller (NVIC)
NVIC_SetPriority(TC8_IRQn, 8); // Set the NVIC priority for TC8 to 8 (medium)
TC2->TC_CHANNEL[2].TC_IER |= TC_IER_LDRAS; // enable interrupt of TC8 on RA loading
TC2->TC_CHANNEL[2].TC_IMR |= TC_IER_LDRAS; // set interrupt mask of TC8 on RA loading
// Enable clock and trigger Timer7:
TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;
}
void TC8_Handler() // ISR TC8 (TC2 Channel 2)
{
if (TC2->TC_CHANNEL[2].TC_SR & TC_SR_LDRAS) // Check for RA load condition
{
introk = 1;
frequ = TC2->TC_CHANNEL[2].TC_RA;
}
}
void loop() {
// put your main code here, to run repeatedly:
if (introk) { // in case of interrupts
introk=0;
Serial.print("f=");Serial.println(frequ);
}
}
If you have a Due you can measure frequency very accurately, but only if the if statement in TC8_Handler() is not commented.
IMO the if statement should not be necessary, but really it is necessary - who knows why?
With the if statement commented there are no outputs to the Serial Monitor. Without such outputs there are no interrupts.
If the interrupt fires then variable introk will be set to 1. And within loop() there will be an output to the Serial Monitor only if introk is set, i.e. if there was an interrupt. Repetition period of interrupts is about 1 sec. Therefore loop() will easyly get every interrupt.
Concerning
wrong moment
The interrupt is defined to fire in the moment when RA is loaded with the counter value at that moment. RA will keep this value for little bit more than a second before the next load will happen. loop() has a lot of time to check if introk is set. How could this checking happen at a wrong moment?
Meantime I added toggling the built in LED within TC8_Handler():
LEDon is declared volatile boolean. In the version as shown above the LED is blinking.
With the if statement commented the LED is constantly on but with low brightness as if it were toggled with PWM with long low period.
My interpretation of this effect is that the Due controller is busy with interrupts.
Or what else could happen?
My assumption that the Due controller is busy with interrupts now is confirmed.
I measured with an oscilloscope at the LED pin and saw a 188 kHz on/off.
Finally reading the Due manual got the solution. Explanations for the status register say: LDRAS: RA Loading Status (cleared on read)
The bit LDRAS is cleared when read and remains on when not read !