stupid datasheet needs more pictures

Hey,
this is what im trying to set up

  • a pwm pulse on dig pin 2, any pin really i dont care as long as it can be prescaled
  • and an interrupt triggered by the pwm capable of running a counter and stopping the pwm pulse and reloading another value :o
#define TMR_LEFT_ON		TC0			// dig pin 2 or 13
#define TMR_CHAN_LEFT_ON	0
#define IRQ_LEFT_ON			TC0_IRQn	        // TC0_Handler

#define TMR_RIGHT_ON		TC2			// dig pin 3 or 10
#define TMR_CHAN_RIGHT_ON	1
#define IRQ_RIGHT_ON		TC7_IRQn	        // TC7_Handler


void start_pwm_with_int()
{
	uint32_t pin2 = digitalPinToBitMask(2);
	
	pmc_set_writeprotect(false);
	
	pmc_enable_periph_clk((uint32_t)IRQ_LEFT_ON);
	
	PIO_Configure(
	g_APinDescription[pin2].pPort,
	PIO_OUTPUT_0,
	g_APinDescription[pin2].ulPin,
	g_APinDescription[pin2].ulPinConfiguration ) ;
	
	PIO_SetPeripheral(PIOA, PIO_PERIPH_B, PIO_PB25);
	
	
	/*
	TC_Configure does the following
		- sets a pointer to the timer, disables the clock in TC_CCR, disables interrupts in TC_IDR
		- clears the status register in TC_SR, sets the mode in TC_CMR
	*/
	TC_Configure	// use the B option to use RB, RC compare
	(
		TMR_LEFT_ON,					// timer instance
		TMR_CHAN_LEFT_ON,				// timer channel
		// configures TC_CMR
		TC_CMR_WAVE |					// Turns on waveform mode
		TC_CMR_WAVSEL_UP_RC |			// UP mode with automatic trigger on RC Compare
		TC_CMR_ACPA_SET |				// RA Compare Effect on TIOA, SET
		TC_CMR_ACPC_CLEAR |				// RC Compare Effect on TIOA, CLEAR
		TC_CMR_TCCLKS_TIMER_CLOCK1
	);
	
	uint32_t RC_val = 10000;
	uint32_t RA_val = RC_val - 1000;
	
	TC_SetRA(TMR_LEFT_ON, TMR_CHAN_LEFT_ON, RA_val);
	TC_SetRC(TMR_LEFT_ON, TMR_CHAN_LEFT_ON, RC_val);
	
	// Enable the RC Compare Interrupts...
	TMR_LEFT_ON->TC_CHANNEL[TMR_CHAN_LEFT_ON].TC_IDR =~ TC_IER_CPCS;
	TMR_LEFT_ON->TC_CHANNEL[TMR_CHAN_LEFT_ON].TC_IER =  TC_IER_CPCS;
	
	
	TC_Start( TMR_LEFT_ON, TMR_CHAN_LEFT_ON );
	
}

It seems that you forgot the Handler. See below an example snippet of TC programming to capture a frequency/duty cycle :

// a jumper needs to be installed between pin 7 (PWM output) and pin A7 (TC0 channel 1 TIOA pin)

volatile uint32_t CaptureCountA, CaptureCountB, TimerCount;
volatile boolean CaptureFlag;

void setup() {
  Serial.begin(250000);                                   // initilize serial port to 250000 baud

  analogWriteResolution(12); // From 0 to 2exp12  - 1 = 4095
  analogWrite(7, 1024);                                   // Duty cycle is 25% with 12 bits resolution

  PMC->PMC_PCER0 |= PMC_PCER0_PID28;                      // Timer Counter 0 channel 1 IS TC1

  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKDIS ;             // disable internal clocking while setup regs

  TC0->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // capture mode, MCK/2, clk on rising edge
                              | TC_CMR_ABETRG              // TIOA is used as the external trigger
                              | TC_CMR_LDRA_RISING         // load RA on rising edge of trigger input
                              | TC_CMR_LDRB_FALLING;       // load RB on falling edge of trigger input

  TC0->TC_CHANNEL[1].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // Trigger interruption on Load RA and load RB
  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Reset TC counter and enable

  //NVIC_DisableIRQ(TC1_IRQn);
  //NVIC_ClearPendingIRQ(TC1_IRQn);
  //NVIC_SetPriority(TC1_IRQn, 0);                      // Give TC1 interrupt the highest urgency
  NVIC_EnableIRQ(TC1_IRQn);                             // Enable TC1 interrupts

  // print the startup header
  Serial.println("Timer Capture");

}


void loop() {
  if (CaptureFlag) {
    CaptureFlag = 0;
    printf("\r %d , %d , %d \n", CaptureCountA, CaptureCountB, TimerCount);
  }
  else {
    Serial.println(TC0->TC_CHANNEL[1].TC_CV);
  }
}

void TC1_Handler() {
 
  //Registers A and B (RA and RB) are used as capture registers. They are loaded with
  //the counter value TC_CV when a programmable event occurs on the signal TIOA.
  TimerCount = TC0->TC_CHANNEL[1].TC_CV;            // save the timer counter register, for testing

  uint32_t status = TC0->TC_CHANNEL[1].TC_SR;       // Read & Save satus register -->Clear status register

  // If TC_SR_LOVRSRA is set, RA or RB have been loaded at least twice without any read
  // of the corresponding register since the last read of the Status Register,
  // We are losing some values,trigger of TC_Handler is not fast enough !!
  if (status & TC_SR_LOVRS) abort();

  if (status & TC_SR_LDRAS) {  // If ISR is fired by LDRAS then ....
    CaptureCountA = TC0->TC_CHANNEL[1].TC_RA;        // get data from capture register A for TC0 channel 1
  }
  else { /* if (status && TC_SR_LDRBS)*/  // If ISR is fired by LDRBS then ....
    CaptureCountB = TC0->TC_CHANNEL[1].TC_RB;         // get data from caputre register B for TC0 channel 1

    CaptureFlag = 1;                      // set flag indicating a new capture value is present
  }

}

thanks ard

i hadnt set up the handler yet because i was under the impression that you could get the output pins to pulse independently(but synced to) of the actual interrupt. just like standard pwm
is that correct

That 's right, you don't need to fire an interrupt to set TIOA, e.g. in this snippet F=1.5 MHz , Duty = 50%:

/*************  Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0  ************/
  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                      // Timer Counter 0 channel 0 IS TC0
  PIOB->PIO_PDR |= PIO_PDR_P25;
  PIOB->PIO_ABSR |= PIO_ABSR_P25;

  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
                              | TC_CMR_ACPC_SET;           // Set TIOA0


  TC0->TC_CHANNEL[0].TC_RC = 28;  //<*********************  Frequency = (Mck/2)/TC_RC  Hz
  TC0->TC_CHANNEL[0].TC_RA = 14;  //<********************   Duty cycle = (TC_RA/TC_RC) * 100  %

  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Reset TC0 counter and enable

cheers
using the pointers is a lot better way to do it

  • is there a way to get the full resolution of MCK using the timer counters, these clocks confuse the sh.. out of me i still dont understand how you can get 84mHz out of a 12mHz crystal.

  • you have had a bit of experience with the PLL clk source, did it work all right for you

  • on page 527 it says the MCK can be prescaled by 1 -> 64, which then supplys the peripheral clk, but in TC_CMR register in only lets you go from prescale 2 to 128, could you please explain why. it seems the peripheral is scaled by 2 from the MCK but i cant see where in the data sheet

Timer counters are clocked from MCK/2 to … but PWMH/L are clocked from MCK to ….

Here is a funny experiment with a PWM frequency of 84 mHz:
http://www.kerrywong.com/2014/09/21/on-arduino-due-pwm-frequency/
MCK = 84 mHz is obtained thru 12 mHz multiplied by the PLL

If you need a Timer clocked at 84 mHz, you can use SysTick->VAL . It is the system timer which counts down (by default, but can be changed) from 84000 to 0 in 1 ms, used by delay(), millis() and micros().

cheers ard

ive been trying to muck around with the 2 examples from above.

can you tell me if this is correct or not. while TC_0 is outputting a pwm signal (ie wave mode) you cannot get the TC0_handler to fire (to run a counter for example)