sync the GCLK0 output and RK output of SSC to F_CPU/32

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi,

I want to synchronise the GCLK0 output and RK output of SSC both to F_CPU/32.

I have 16MHz on OSC0 and I start SSC_RX in falling edge of RF signal.

Here is what I did:

void power_on_reset(void)
{  
// first select OSC1 as clock source of GCLK0, so that the Divider is not triggered after OSC0 is enabled.
  pm_gc_setup(pm,
              0,  // GCLK0
              1,  // Use Osc (=0) or PLL (=1), here PLL
              0,  // Sel Osc0/PLL0 or Osc1/PLL1
              1,  // enable divisor
              15); // div by 32

	// Swith to external Oscillator 0.
	pm_switch_to_osc0(pm, FOSC0, OSC0_STARTUP);

// connect OSC0 to GCLK0
  pm_gc_setup(pm,
              0,  // GCLK0
              0,  // Use Osc (=0) or PLL (=1), here PLL
              0,  // Sel Osc0/PLL0 or Osc1/PLL1
              1,  // enable divisor
              15); // div by 32

_delay_cycles(21); // this value can be tuned to sync GCLK0 and RK of SSC clocks

// connect OSC0 to SSC
ssc->cmr = 16; // MCK/32
	
	ssc->rcmr = (2 << AVR32_SSC_RCMR_CKO_OFFSET) | AVR32_SSC_RCMR_CKI_MASK | (AVR32_SSC_RCMR_START_DETECT_FALLING_RF << AVR32_SSC_RCMR_START_OFFSET) | (1 << AVR32_SSC_RCMR_STTDLY_OFFSET);
	
	ssc->rfmr = ((24 - 1) << AVR32_SSC_RFMR_DATLEN_OFFSET) | AVR32_SSC_RFMR_MSBF_MASK | ((4 - 1) << AVR32_SSC_RFMR_DATNB_OFFSET) | AVR32_SSC_RFMR_FSEDGE_MASK;
	
	ssc->cr = AVR32_SSC_CR_RXEN_MASK;	


}

Afterwards, I stared the peripheral on SSC RX and loocked at the waveforms of GCLK0 and RK of SSC on oscilloscope, and phases of two waveform are different each time I power on my board, this is so strange. Shouldn't the phase be the same? Because it's the same piece of the code.

anyone know why?

Cheng

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Cheng,

Note that your first call to pm_gc_setup selects fGCLK0 = fPLL0 / 32, not fOSC1 / 32 as stated by your comment.

Moreover, switching a GCLK to a non-existing clock source is not advised.

You should also check that FOSC0 is defined to 16 MHz and that OSC0_STARTUP fits your crystal characteristics. If you are using an external clock and not a crystal, you should not use pm_switch_to_osc0 but the functions it calls with the external clock mode.

You can try to replace the beginning of your function with the following:
- Start Osc0 without switching the main clock to it (use the two first source code lines from pm_switch_to_osc0).
- Wait for some synchronization value in the COUNT system register (you are still running on the RCOsc @ 115,200 Hz at this time). Choose this value large enough so that it is always the first time COUNT reaches this value from MCU POR until Osc0 is ready.
- Switch the main clock to Osc0.
- Keep the end of your function from the last call to pm_gc_setup.

This will not guarantee synchronization of GCLK0 and SSC RK, but it will help keeping a constant phase from one startup to the other. For synchronization, adjust your value in _delay_cycles.

You can also try to switch the main clock to Osc0 at the end of your function rather than after the synchronization on COUNT.

++
Ben

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, Ben

thanks for the reply.

I use a 16MHz crystal on OSC0 and yes, FOSC0 is 16MHz and OSC0_STARTUP is fine with the crystal.

I still don't understand why my code would have different phase after each power-up.

I can delete the:

// first select OSC1 as clock source of GCLK0, so that the Divider is not triggered after OSC0 is enabled. 
  pm_gc_setup(pm, 
              0,  // GCLK0 
              1,  // Use Osc (=0) or PLL (=1), here PLL 
              0,  // Sel Osc0/PLL0 or Osc1/PLL1 
              1,  // enable divisor 
              15); // div by 32 

and try again, but this code shouldn't give the uncertain phase, right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW,

I just notice the following interesting code:

static void pm_set_osc0_mode(volatile avr32_pm_t *pm, unsigned int mode)
{
  // Read
  u_avr32_pm_oscctrl0_t u_avr32_pm_oscctrl0 = {pm->oscctrl0};
  // Modify
  u_avr32_pm_oscctrl0.OSCCTRL0.mode = mode;
  // Write
  pm->oscctrl0 = u_avr32_pm_oscctrl0.oscctrl0;
}

Is this some special way to let the AVR32GCC automatically use MEMC or MEMS instruction?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

darthvader wrote:
but this code shouldn't give the uncertain phase, right?

Right. I think this uncertain phase may come either from the RCOsc startup time or from the Osc0 startup time, hence the synchronization with COUNT I suggested using RCOsc as main clock before switching the main clock to Osc0.

darthvader wrote:
Is this some special way to let the AVR32GCC automatically use MEMC or MEMS instruction?

No. This way of writing the code was useful with older versions of the AVR32 GNU Toolchain to access volatile bit-fields.

For instance,

pm->OSCCTRL0.mode = mode;

could have generated LD.UB/ST.UB instructions, what is not supported by the PBA interface of peripherals like the PM. The 32-bit width of the OSCCTRL0 bit-field should be used by the compiler here, hence this special code.

This issue no longer happens with the latest compiler from the AVR32 GNU Toolchain 2.x.

You should also note that the MEMC/MEMS/MEMT instructions were not supported to access peripheral registers prior to UC3A rev. H as specified by the erratum 41.2.5.3 in the datasheet (http://www.atmel.com/dyn/resources/prod_documents/doc32058.pdf).

++
Ben

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, I will try with COUNT register again, thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, I found the reason.

It's because the GCLK in disable mode always keep its prescaler reset. So I just need to enable SOC0 and select it as main clock and then set and enable GCLK0 and then set the presccaler of SSC and enable SSC. And now I always get the same phase.