SAMC21 Main clock, peripheral clock and clock domain synchronization

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

Hello,

 

As the SAMC21 need synchronizes between clock domains for certain operations, is it better to have (if possible) the peripheral clocks with the same speed as the main clock and use prescalers to get the right clock speed? I am thinking about the delays the synchronization could add to the operations, especially for operations that are done frequently. Is this a valid concern or does it really not matter?

 

Thank you!

Andre

 

This topic has a solution.
Last Edited: Wed. Sep 23, 2020 - 07:42 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bumpy McBumpface

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

Can't say I've noticed any significant delays when syncing across clock domains. If you're concerned, you could tweak the sync loops to track the number of iterations required for various clock ratios. Dump the stats periodically and pick what ratio(s) work best for you.

 

Steve

Maverick Embedded Technologies Ltd. Home of Maven and wAVR.

Maven: WiFi ARM Cortex-M Debugger/Programmer

wAVR: WiFi AVR ISP/PDI/uPDI Programmer

https://www.maverick-embedded.co...

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

 track the number of iterations required for various clock ratios.

What would be a good way of doing this? Toggle pin between the synchronization loops and measure the time with a scope or logic analyzer? 

 

Andre

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No need to go that far. Something similar to the following example will be adequate in most cases:

static unsigned int sync_total_loops;
static unsigned int sync_calls;

static void
sam_usart_syncbusy(SercomUsart *u, uint32_t mask)
{
        unsigned int loops = 0;

        sync_calls++;

        while ((u->SYNCBUSY.reg & mask) != 0)
                loops++;

        sync_total_loops += loops;
}

void
show_sync_stats(void)
{

        if (sync_calls != 0) {
                printf("Calls: %u, Loops %u, Average loops per call %u\n",
                    sync_calls, sync_total_loops, sync_total_loops / sync_calls);
        }
}

Call "show_sync_stats()" periodically from the main loop, for various clock ratios. This will give you a rough idea how many CPU cycles you're "wasting" per sync.

 

Steve

Maverick Embedded Technologies Ltd. Home of Maven and wAVR.

Maven: WiFi ARM Cortex-M Debugger/Programmer

wAVR: WiFi AVR ISP/PDI/uPDI Programmer

https://www.maverick-embedded.co...

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

Thank you for the input, I will try this out soon and post my results yes

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

Hello,

 

The advice Steve gave was spot on, the synchronization of clock domains (mostly) does not have a significant delay. I tested this on a free running timer clocked by a 8MHz clock with source clock being 48Mhz, the timer clock was pre scaled to 1MHz.

    TC0->COUNT32.CTRLBSET.bit.CMD = 4u;
    while (TC0->COUNT32.SYNCBUSY.bit.CTRLB == 1u) {/* MISRA */};

    return TC0->COUNT32.COUNT.reg;

To read out the counter value it must be read synced. The delay for the synchronization was 1 or 2 cycles at most, the main clock and peripheral ratio is then 48:1.

When I checked watchdog kick (register clear) synchronization delay then this was quite high. The watchdog is sourced from the internal low power 32kHz clock running at 1kHz. The delay count was ~6000.

 

I am being general here, but it seems that peripheral clocks sourced from the main clock do not have a significant delay, other low frequency clock sources need some care.

 

Andre