Clock speed for PDB: Tested on Teensy 3.2 and 3.5

Status
Not open for further replies.

MichaelT

Member
Hi, as an introduction to PDB and DMA I was trying to work through the tutorial at https://courses.cs.washington.edu/courses/cse466/15au/labs/l5/l5.html and have written the Arduino blink sketch posted below. This works on both Teensy 3.2 and 3.5 selecting a CPU speed of 48 MHz from the "Tools" menu option. However, the LED does not blink at all at the higher clock speeds (e.g. 72 MHz, 96 MHz) and I do not understand why. Can someone explain why and help me find the solution?

Code:
// PDB 0 Status and Control Register  
#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_PRESCALER(7) | PDB_SC_MULT(1))
//(PDB_SC_TRGSEL(n)       //  B8-B11  Software trigger is selected
//|PDB_SC_PDBEN           //  B7      PDB enable
//|PDB_SC_PDBIE           //  B5      Interrupt enable
//|PDB_SC_CONT            //  B1      Continuous mode
//|PDB_SC_PRESCALER(n)    //  B12-B14 Counting uses peripheral clock divided by multiplication factor
//|PDB_SC_MULT(1)     )   //  B2-B3   Prescaler multiplication factor = 10 (00=1,01=10,10=20,11=40)

#define PDB_PERIOD 37500  // 1 Hz at 48 MHz clock speed

void setup() {
pinMode(13, OUTPUT);
GPIOC_PDDR |= (1 << 5);
GPIOC_PCOR |= (1 << 5);

// Enable PDB clock module in System Clock Gating Control Register 6
 SIM_SCGC6 |= SIM_SCGC6_PDB;  

// PDB 0 Modulus Register specifies the counter top value (resets to zero on reaching this value)
// If the counter is in continuous mode, it will continue counting from 0
// Set to 1/(48 MHz / 128 prescaler / 10) * 37500 = 1 s
 PDB0_MOD = PDB_PERIOD;  //1 = 9.36khz  
 PDB0_IDLY = 0;             // Interrupt delay = 0  
 PDB0_SC |= PDB_CONFIG;     // Set status and control register
 PDB0_SC |= PDB_SC_SWTRIG;  // Software trigger enable (reset and restart counter)
 PDB0_SC |= PDB_SC_LDOK;    // Load OK 
 NVIC_ENABLE_IRQ(IRQ_PDB);  // Enable interrupt request  
}

void loop() {}

void pdb_isr() {
   GPIOC_PTOR |= (1<<5); // toggle pin 13 each interrupt
   PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; // (also clears interrupt flag)
}
 
try reordering the statements in the isr
Code:
void pdb_isr() {
  PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; // (also clears interrupt flag)
  GPIOC_PTOR |= (1 << 5); // toggle pin 13 each interrupt
}
Also, note the PDB ticks at the speed of F_BUS. For F_CPU at 48mhz and 96mhz, F_BUS will be 48mhz, but for F_CPU@72mhz, F_BUS is 36mhz, so PDB_PERIOD may need adjusting. If you want the PDB period to be N ticks, you load N-1 in PDB0_MOD. PDB0_MOD is only 16 bits, so you have to adjust prescale and multiplier so that period "fits" in 16-bits.
 
Last edited:
if you count interrupts in the isr (cnt++) and print cnt every second in loop, you will see for your sketch at high CPU speed, it is counting 2 interrupts every second. isr is firing twice. If you reorder to clear the interrupt first thing in the isr, then that provides a delay for the interrupt flag to clear. Paul and others can probably provide a more accurate explanation. One could also spin-wait in the isr for the flag to be cleared in PDB0_SC
 
OK. Thanks! Much appreciated. I forgot to say that this made my program work, even 168 MHz CPU speed (overclock) option on Teensy 3.5.
 
Status
Not open for further replies.
Back
Top