Go Down

Topic: stupid datasheet needs more pictures (Read 252 times) previous topic - next topic

joeblogs

Mar 20, 2017, 11:24 am Last Edit: Mar 20, 2017, 12:37 pm by joeblogs
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
Code: [Select]


#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 );

}



ard_newbie

#1
Mar 20, 2017, 01:34 pm Last Edit: Mar 21, 2017, 02:50 am by ard_newbie
It seems that you forgot the Handler. See below an example snippet of TC programming to capture a frequency/duty cycle :

Code: [Select]

// 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
  }

}




joeblogs

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

ard_newbie

#3
Mar 21, 2017, 02:56 am Last Edit: Mar 21, 2017, 03:00 am by ard_newbie
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%:

Code: [Select]

/*************  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





joeblogs

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

ard_newbie

#5
Mar 21, 2017, 07:33 am Last Edit: Mar 21, 2017, 07:34 am by ard_newbie
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().

joeblogs


joeblogs

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)

Go Up