I got a new Arduino Due and wanted to setup a 4,2MHz Timer. I used the Timer formula :
84Mhz/2 = 42 Mhz
42Mhz/4.2Mhz = 10 -> Counter Period =10
but I only get a Timer of 1.5MHz. The formula works perfectly fine until the Counter Period of 28 (1.5MHz) then it somehow gets messed up. Can somebody explain this to me? Plus can somebody explain to me the first 5 lines of the setup? Why do I need to set the corresponding PIN?
Code:
volatile boolean l;
int i = 0;
void TC6_Handler()
{
long dummy=REG_TC2_SR0;
l = !l;
if ( l) {
REG_PIOC_SODR = 1 <<23;
}else{
REG_PIOC_CODR = 1<<23;
}
}
void setup(){
pinMode(7,OUTPUT);
pinMode(4,OUTPUT); // port C pin 26
analogWrite(4,255); // sets up some other registers I haven't worked out yet
REG_PIOC_PDR = 1<<26; // disable PIO, enable peripheral
REG_PIOC_ABSR= 1<<26; // select peripheral B
REG_TC2_WPMR=0x54494D00; // enable write to registers
REG_TC2_CMR0=0b00000000000001011100000000000000;
REG_TC2_RC0=10; // counter period
REG_TC2_CCR0=0b101; // start counter
REG_TC2_IER0=0b00010000; // enable interrupt on counter=rc
REG_TC2_IDR0=0b11101111; // disable other interrupts
NVIC_EnableIRQ(TC6_IRQn); // enable TC6 interrupts
}
void loop(){
//digitalWrite(7,l);
}
A few thoughts about your code:
Since you are using magic numbers, it's a pain to debug. It's much better to use names you will find in the datasheet and in header files
https://android.googlesource.com/platform/external/arduino-ide/+/f876b2abdebd02acfa4ba21e607327be4f9668d4/hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/component
You want an interrupt at a 4.2 MHz frequency, this leaves your interrupt code 20 clock cycles to enter, process your interrupt code, and exit from the interrupt... This is an isssue ! Maybe you could find a workaround by adding attribute ( ( naked ) ) before the interrupt Handler function and reduce to the minimum your actual code Inside the interrupt to toggle a pin (not tested though).
Here is an example sketch with Timer Counter 0 Channel 0 paced at 1 MHz to toggle an LED Inside the interrupt Handler every 1 Hz:
/***************************************************************************************/
/* Timer Counter 0 Channel 0 - PWM frequency = 1 MHz */
/**************************************************************************************/
void setup() {
PMC->PMC_PCER0 |= PMC_PCER0_PID12; // PIOB power ON
PIOB->PIO_OER |= PIO_OER_P27;
PIOB->PIO_OWER |= PIO_OWER_P27; // Built In LED output write enable
/************* Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0 ************/
PMC->PMC_PCER0 |= PMC_PCER0_PID27; // TC0 power ON - Timer Counter 0 channel 0 IS TC0
PIOB->PIO_PDR |= PIO_PDR_P25; // The pin is no more driven by the GPIO
PIOB->PIO_ABSR |= PIO_PB25B_TIOA0; // TIOA0 (pin 2) is PB25 peripheral type B
TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // MCK/2, 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 TIOA0 on RA compare match
| TC_CMR_ACPC_SET; // Set TIOA0 on RC compare match
TC0->TC_CHANNEL[0].TC_RC = 42; //<********************* Frequency = (Mck/2)/TC_RC Hz = 1 MHz
TC0->TC_CHANNEL[0].TC_RA = 5; //<******************** Any Duty cycle between 1 and TC_RC, Duty cycle = (TC_RA/TC_RC) * 100 %
TC0->TC_CHANNEL[0].TC_IER = TC_IER_CPCS; // Interrupt on RC compare match
NVIC_EnableIRQ(TC0_IRQn); // TC1 Interrupt enable
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC0 counter and enable
}
void TC0_Handler() {
static uint32_t Count = 1000000;
TC0->TC_CHANNEL[0].TC_SR; // Read and clear status register
Count--;
if (Count == 0) {
PIOB->PIO_ODSR ^= PIO_ODSR_P27; // Toggle LED with a 1 Hz frequency
Count = 1000000;
}
}
void loop() {
}
Note that you can toggle a pin (TIOA0) with a very high frequency without any interruption.