Arduino Due - route internal clock to PCKx

HW = Arduino Due and Wolfson WM8737 Audio ADC Arduinoe SW version = 1.5.5 Computer: Mac OSX 10.9.1

Problem: The Wolfson ADC requires a 12MHz clock. The internal MAINCLK of the SAM3X is the buffered crystal frequency of 12MHz. The SAM3X Programmable Clock Output Controller PCOC allows MAINCLK to be routed to one of the PCKx (x = 0,1,2) pins.

On the Due board, some pin options for PCKx are: PCK0 = PA1 mapped to CANRX , pin 68 PCK1 = PA24 mapped to analog in A3, pin 55 PCK2 = PA28 mapped to NPCSO (SPI), pin 77

32 bit Registers that control PCOC are: PMC_SCER (PMC System Clock Enable Register) address is 0x400E0600, write only, PMC_SCDR (PMC System Clock Disable Register) address is 0x400E0604, write only, PMC_SCSR (PMC System Clock Status Register) address is 0x400E0608, read only. PMC_PCKx (PMC Programmable Clock Register) address is 0x400E0640, read/write. PMC_WPMR (PCM Write Protect Mode Register) address is 0x400E06E4, read-write. (PMC_SCER and PMC_SCDR and PMC_PCKx can only be written to if the WPEN bit is in the PMC Write Protect Mode Register)

My experimental code is below. There are several embedded questions. The code compiles, yet there is no clock signal on the PCK0 pin 68. The Serial.print result for the status register is 100001 which should have been 100000000 for PCK0 active.

Both PMC->register name and REG_registername methods resulted in the same lack of PCK0 activation.

Both REG_PMC_SCER |= 0x100; and REG_PMC_SCER = 0x100; resulted in a status read back of 100001 (bit 8 low).

Thanks

void setup() 
{
  Serial.begin(9600);
  // Define PA1 (PCK0) as an digital output pin
  // DDRA = (DDRA | 0x1);    // ERROR; 'DDRA' was not declared in this scope 
  // Question: DDRA works with ATmega2560, SAM3X is different?
  pinMode (68, OUTPUT);      // pin 68 is PA0 - needed for PCK0
  // Question: does this override the default Arduino CANRX mapping for this pin?
}

void loop()
{
  // Enable writing to PCOC registers
  // PMC->PMC_WPMR = 0x504D4301;    // bit 0 high sets the WPEN value
  REG_PMC_WPMR = 0x504D4301;         // either register assignment compiles
  
  // Select the MAINCLK and set the divider to /1;
  //REG_PMC_PCK0 |= 0x1;   // ERROR: " 'REG_PMC_PCK0' was not declared in this scope". Is this a invalid command?
                           // PMC_PCK0 is defined as a valid register name in Table 29-3.
  PMC->PMC_PCK[0] = 0x1;   // From forum "ARDUINO DUE PMC REGISTERS" June 6 2013
  // CSS assigned to  bits 0 - 2,  CSS = 1 selects the Main (crystal) Clock. 
  // PRES assigned to bits 4 – 6, PRES = 0  is associated with “divide by 1” option.

  // Route internal clock to PCK0
  // PMC->PMC_SCER |= 0x100;    // bit 8 high enables PCK0  (B100000000)
  REG_PMC_SCER |= 0x100;  
  // Disconnect PCK0 from internal clocks
  // PMC_SCDR =| 0x100) ;    // bit 8 high disables PCK0

  // Disable writing to PCOC registers
  // PMC->PMC_WPMR = 0x504D4300;    // bit 0 low resets the WPEN value
  REG_PMC_WPMR = 0x504D4300;

  // To verify the status of PCK0, read PMC_SCSR  and verify bit 8 is high
  // Serial.println (“the 8th bit of the PMC System Clock Status Register is  PCK0 status“);
  // The line above creates many errors in Beta 1.5
  Serial.println (REG_PMC_SCSR, BIN);
  
  while(1);
}
  REG_PMC_WPMR = 0x504D4301;

I think you have this the wrong way round - 0x504D4301 enables write protection (and disables being able to write to the registers), 0x504D4300 disables write protection (enables writing the registers)

Thanks Stimmer,

"0 = disable protect" I must have tripped on too many negatives. (Poor excuse, but the only I have.)

The REG_PMC_SCSR status report is 100100001, so PCK0 is active. Still the PKC0 pin 68 goes and stays high, no clock seen yet. Using PMC-> register name instead of REG_registername makes no difference, although I have a more intuitive understanding of the later. I have to leave town for 36 hours, but when I get back, I will triple check my register settings. In the meanwhile, I would like to ask some general Due coding questions:

  1. pinMode (68, OUTPUT); // pin 68 is PA0 - needed for PCK0 // Question: does this override the default Arduino CANRX mapping for this pin?

  2. REG_PMC_PCK0 |= 0x1; // ERROR: " 'REG_PMC_PCK0' was not declared in this scope". Is this a invalid command? // PMC_PCK0 is defined as a valid register name in Table 29-3, I think. PMC_PCKx actually, where x could = 0?

  3. Serial.println (“the 8th bit of the PMC System Clock Status Register is PCK0 status“); // The line above creates many errors in Beta 1.5 - I have the feeling I am doing something dumb here.

Regards, Greg

What you need to do is to set the PIO registers to allow peripherla control of the pin. Use PIOA->PIO_PDR= to disable PIO and enable peripheral control for the relevant pin, and then set PIOA->PIO_ABSR |= or &=~ correctly to pick the right peripheral. Read the datasheet section 11 to find if it's peripheral A or B, then section 32 for the PIO registers.

Hi, the following sequence gives me 84Mhz on the PCK0 (CANRX) pin...

REG_PIOA_WPMR = 0x50494F00; // enable writes REG_PIOA_PDR = 0x02; // enable peripheral control REG_PIOA_ABSR = 0x02; // A-B select? REG_PIOA_WPMR = 0x50494F01; // disable writes

REG_PMC_WPMR = 0x504D4300; // enable writes REG_PMC_SCER = 0x100; PMC->PMC_PCK[0] = 0x4; // master clock = 84Mhz REG_PMC_WPMR = 0x504D4301; // disable writes

...hope this helps.

bre1 - many thanks, your code works. I see 84MHz on the CANRX pin. (I would have replied earlier but have been on the road.) So now I will try to repeat with routing out the Main clock (12MHz) and will post my results. Regards.

Simple change to PMC->PMC_PCK[0] below provides the Main Clock (crystal freq) at CANRX pin

REG_PIOA_WPMR = 0x50494F00; // enable writes REG_PIOA_PDR = 0x02; // enable peripheral control REG_PIOA_ABSR = 0x02; // A-B select? REG_PIOA_WPMR = 0x50494F01; // disable writes

REG_PMC_WPMR = 0x504D4300; // enable writes REG_PMC_SCER = 0x100; PMC->PMC_PCK[0] = 0x1; // master clock = 12Mhz (crystal freq) REG_PMC_WPMR = 0x504D4301; // disable writes

Update, two modifications:

  1. used |= instead of just = in order to assure only the Due CANRX port is modified.
  2. many registers have separate enable and disable registers. I assume that it is wise to write to both to avoid conflicting status. added this line REG_PIOA_PER &= ~0x02; // prevents disabling peripheral control of the pin
void setup() 
{
  Serial.begin(9600);
}

void loop()
{
  REG_PIOA_WPMR = 0x50494F00;  // enable writes
  REG_PIOA_PDR |= 0x02;        // enable peripheral control
  REG_PIOA_PER &= ~0x02;        // Prevents disabling peripheral control of the pin
  REG_PIOA_ABSR |= 0x02;       // B preipherial select
  REG_PIOA_WPMR = 0x50494F01;  // disable writes

  REG_PMC_WPMR = 0x504D4300;   // enable writes
  REG_PMC_SCER |= 0x100;
  PMC->PMC_PCK[0] = 0x1;       // master clock = 12Mhz (crystal freq)
  REG_PMC_WPMR = 0x504D4301;   // disable writes

  while(1);
}

Thank you so much for posting this! I am trying to use the exact same Wolfson chip and just couldn't get a working clock signal output... But since i was trying to use an external oscillation crystal for this purpose, i thought that you could maybe help with that? I would like to use an external clock signal for the wolfson chip, which outputs a clock that should be used by the arduino. But I am just not able to generate a timer interrupt from an external clock signal. :roll_eyes:

You don't need to use the write-enable magic numbers unless you've deliberately turned on the mechanism that requires them. They are there for safety-critical systems where the consequences of a crash must be limited (albeit probablistically).

Micheal, It has been many weeks, I was out of the country. Now back, I wonder how you are doing with the Wolfson audio ADC project? Greg