{"id":314,"date":"2025-07-26T19:52:27","date_gmt":"2025-07-26T18:52:27","guid":{"rendered":"https:\/\/blog.edgesmart.co.uk\/?p=314"},"modified":"2025-07-27T16:14:02","modified_gmt":"2025-07-27T15:14:02","slug":"cdc-101-1-clock-domains-cdc-safety","status":"publish","type":"post","link":"https:\/\/blog.edgesmart.co.uk\/index.php\/2025\/07\/26\/cdc-101-1-clock-domains-cdc-safety\/","title":{"rendered":"CDC-101.1 Fundamentals of Clock Domain(s)"},"content":{"rendered":"\n<p>In digital design, particularly in FPGA development, managing signal transfers across different clock domains is critical. Failure to handle Clock Domain Crossing (CDC) correctly can lead to elusive, non-reproducible bugs that are nearly impossible to debug in post-silicon. This blog post explores the fundamentals of clock domains, when clocks are considered asynchronous, and why CDC safety is non-negotiable, even between seemingly related clocks.<\/p>\n\n\n\n<p><strong>What Are Clock Domains in Digital Design?<\/strong><\/p>\n\n\n\n<p>In digital systems like FPGAs and ASICs, a <strong>clock domain<\/strong> is a group of registers (flip-flops) and logic that are <strong>driven by the same clock signal<\/strong>.<\/p>\n\n\n\n<p><strong>Formal Definition:<\/strong><\/p>\n\n\n\n<p>A <strong>clock domain<\/strong> is a region of a digital design in which all sequential elements (e.g., flip-flops, latches, memory blocks) are <strong>triggered by the same clock source<\/strong>, or a clock signal that is phase-aligned and frequency-matched.<\/p>\n\n\n\n<p><strong>Why Do Clock Domains Exist?<\/strong><\/p>\n\n\n\n<p>Most real-world digital designs use <strong>multiple clocks<\/strong>. Reasons include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Different functional blocks running at different speeds (e.g., CPU vs. peripherals)<\/li>\n\n\n\n<li>External interfaces needing specific clocks (e.g., HDMI, Ethernet, DDR)<\/li>\n\n\n\n<li>Power-saving (lower clocks in idle regions)<\/li>\n\n\n\n<li>IP blocks with their own clocks<\/li>\n\n\n\n<li>Asynchronous inputs (buttons, sensors)<\/li>\n<\/ul>\n\n\n\n<p>T<strong>ypes of Clock Domain Relationships<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Type<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Single Clock Domain<\/strong><\/td><td>Everything runs off the same clock. Timing is simple.<\/td><\/tr><tr><td><strong>Synchronous Domains<\/strong><\/td><td>Clocks are related (e.g., same MMCM\/PLL source, fixed phase\/frequency relationship)<\/td><\/tr><tr><td><strong>Asynchronous Domains<\/strong><\/td><td>Clocks are unrelated (e.g., separate crystals or PLLs). Need CDC handling.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Why Clock Domains Crossings Matter<\/strong>?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When signals <strong>stay within the same clock domain<\/strong>, timing is predictable and safe.<\/li>\n\n\n\n<li>When signals <strong>cross from one domain to another<\/strong>, you must use <strong>Clock Domain Crossing (CDC)<\/strong> techniques to avoid <strong>metastability<\/strong> and <strong>timing errors<\/strong>.<\/li>\n\n\n\n<li><strong>Static Timing Analysis (STA)<\/strong> works only within a clock domain or across known, related clocks.<\/li>\n<\/ul>\n\n\n\n<p><strong>Problems Without Proper Clock Domain Crossing<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Metastability<\/strong>: Occurs if a flip-flop samples data during a transition from another clock domain.<\/li>\n\n\n\n<li><strong>Data loss or corruption<\/strong>: Multi-bit signals crossing domains can glitch.<\/li>\n\n\n\n<li><strong>False timing violations<\/strong>: If timing tools (like Vivado) don\u2019t know clocks are unrelated, they\u2019ll report invalid errors or waste build time.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>When Are Two Clock Domains Called Asynchronous?<\/strong><\/p>\n\n\n\n<p>Two clock domains are called <strong>asynchronous<\/strong> when: <strong>There is no known, fixed phase or frequency relationship between the two clocks.<\/strong><\/p>\n\n\n\n<p>This means:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Their rising and falling edges do <strong>not align<\/strong> in any predictable way<\/li>\n\n\n\n<li>They are derived from <strong>independent sources<\/strong> (e.g., separate oscillators or PLLs)<\/li>\n\n\n\n<li>One may drift or jitter with respect to the other over time<\/li>\n<\/ul>\n\n\n\n<p><strong> Asynchronous Clocks \u2014 Examples<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Clock A<\/strong><\/td><td><strong>Clock B<\/strong><\/td><td><strong>Asynchronous?<\/strong><\/td><\/tr><\/thead><tbody><tr><td>100\u202fMHz from onboard oscillator<\/td><td>66\u202fMHz from external interface<\/td><td>Yes<\/td><\/tr><tr><td>100\u202fMHz from PLL0<\/td><td>125\u202fMHz from PLL1<\/td><td>Yes (usually)<\/td><\/tr><tr><td>50\u202fMHz system clock<\/td><td>Button input debounced at 1\u202fHz<\/td><td>Yes<\/td><\/tr><tr><td>Ethernet RX clock<\/td><td>FPGA system clock<\/td><td>Yes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Unless there is a <strong>documented, locked phase relationship<\/strong> (e.g., derived from same PLL with known divider), <strong>assume clocks are asynchronous<\/strong>.<\/p>\n\n\n\n<p><strong>The Key Idea:<\/strong><\/p>\n\n\n\n<p>Asynchronous clocks can shift in time relative to each other <strong>infinitely<\/strong>. Even if they\u2019re close in frequency (e.g., 100 MHz and 101 MHz), their edges will align occasionally and misalign again \u2014 unpredictably.<\/p>\n\n\n\n<p>This makes it <strong>unsafe to directly pass data between them<\/strong>.<\/p>\n\n\n\n<p><strong>What if Frequencies Are Related?<\/strong><\/p>\n\n\n\n<p>If two clocks are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Generated from the <strong>same PLL\/MMCM<\/strong><\/li>\n\n\n\n<li>Have a <strong>fixed phase\/frequency relationship<\/strong><\/li>\n\n\n\n<li>And the design <strong>knows<\/strong> that relationship<\/li>\n<\/ul>\n\n\n\n<p>\u2026then they may be treated as <strong>synchronous<\/strong> (e.g., clk and clk\/2).<\/p>\n\n\n\n<p>But if there&#8217;s any <strong>jitter<\/strong>, <strong>independent PLLs<\/strong>, or <strong>external clocks<\/strong>, then they are <strong>asynchronous<\/strong> by definition.<\/p>\n\n\n\n<p><strong>Engineering Rule of Thumb<\/strong><\/p>\n\n\n\n<p>Unless you can <strong>prove<\/strong> the clocks are phase-aligned and frequency-locked, treat them as <strong>asynchronous<\/strong> and use proper <strong>CDC design<\/strong> and <strong>constraints<\/strong>.<\/p>\n\n\n\n<p><strong>Why It Matters in Vivado<\/strong>?<\/p>\n\n\n\n<p>Vivado can only do valid <strong>Static Timing Analysis (STA)<\/strong> when it knows the relationship between clocks.<\/p>\n\n\n\n<p>If clocks are <strong>asynchronous<\/strong>, you must:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use proper CDC techniques<\/li>\n\n\n\n<li>Cut invalid paths with constraints<\/li>\n<\/ul>\n\n\n\n<p>Otherwise, Vivado will try to time them and report <strong>false setup\/hold violations<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Clock Relationships<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Term<\/strong><\/td><td><strong>What It Means<\/strong><\/td><td><strong>Example<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Edge-aligned<\/strong><\/td><td>The rising (or falling) edges of both clocks occur at the <strong>exact same moment<\/strong> periodically<\/td><td>100\u202fMHz and 100\u202fMHz clocks with 0\u00b0 phase shift<\/td><\/tr><tr><td><strong>Phase-aligned<\/strong><\/td><td>The clocks have a <strong>fixed, known phase offset<\/strong> (e.g., one always lags the other by 90\u00b0 or 2.5\u202fns)<\/td><td>100\u202fMHz and 100\u202fMHz with 90\u00b0 shift<\/td><\/tr><tr><td><strong>Phase-related<\/strong><\/td><td>The clocks are derived from the same source and their frequency\/phase relationship is <strong>deterministic<\/strong>, but their edges <strong>don\u2019t align<\/strong> regularly<\/td><td>100\u202fMHz and 66.67\u202fMHz from same MMCM<\/td><\/tr><tr><td><strong>Asynchronous<\/strong><\/td><td>Clocks have <strong>no fixed phase or frequency relationship<\/strong>; edges drift relative to each other<\/td><td>100\u202fMHz from onboard oscillator and 27\u202fMHz from external sensor<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Edge-Aligned Clocks<\/strong><\/p>\n\n\n\n<p><strong>Breakdown with Examples<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Frequency: same<\/li>\n\n\n\n<li>Phase: 0\u00b0<\/li>\n\n\n\n<li>Edges rise <strong>together<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Example:<\/p>\n\n\n\n<p>clkA: |\u203e\u203e\u203e|___|\u203e\u203e\u203e|___|\u203e\u203e\u203e<\/p>\n\n\n\n<p>clkB: |\u203e\u203e\u203e|___|\u203e\u203e\u203e|___|\u203e\u203e\u203e<\/p>\n\n\n\n<p>Used in synchronous multi-clock systems (e.g., when using a BUFG or create_generated_clock in Vivado).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Phase-Aligned (but Not Edge-Aligned)<\/strong> <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Frequency: same<\/li>\n\n\n\n<li>Phase: fixed (e.g., 90\u00b0 shift)<\/li>\n\n\n\n<li>Edges don\u2019t align, but timing is <strong>predictable<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Example:<\/p>\n\n\n\n<p>clkA: |\u203e\u203e\u203e|___|\u203e\u203e\u203e|___|\u203e\u203e\u203e<\/p>\n\n\n\n<p>clkB:&nbsp;&nbsp; |\u203e\u203e\u203e|___|\u203e\u203e\u203e|___|<\/p>\n\n\n\n<p>Used for DDR interfaces, skewed clocks for hold violation fixing, etc.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Phase-Related, Edge-Misaligned<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Different frequencies (but derived from same MMCM)<\/li>\n\n\n\n<li>LCM (Least Common Multiple) of periods may make them <strong>coincide sometimes<\/strong><\/li>\n\n\n\n<li>But in general, edges drift<\/li>\n<\/ul>\n\n\n\n<p>Example:<br>100\u202fMHz (10\u202fns) and 66.67\u202fMHz (15\u202fns)<\/p>\n\n\n\n<p>clkA: |\u203e\u203e\u203e|___|\u203e\u203e\u203e|___|\u203e\u203e\u203e<\/p>\n\n\n\n<p>clkB: |\u203e\u203e\u203e\u203e\u203e|_____|\u203e\u203e\u203e\u203e\u203e|<\/p>\n\n\n\n<p>These are <strong>synchronous<\/strong> in terms of Vivado (same MMCM), but potentially <strong>not safe for direct sampling<\/strong> \u2014 they may need CDC logic.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Asynchronous<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>No stable frequency or phase relationship<\/li>\n\n\n\n<li>Edges are <strong>unpredictable<\/strong> with respect to each other<\/li>\n<\/ul>\n\n\n\n<p>Example:<\/p>\n\n\n\n<p>clkA: |\u203e\u203e\u203e|___|\u203e\u203e\u203e|___|\u203e\u203e\u203e<\/p>\n\n\n\n<p>clkB:&nbsp;&nbsp; |\u203e\u203e\u203e\u203e\u203e|_____|\u203e\u203e\u203e\u203e\u203e|<\/p>\n\n\n\n<p>These require CDC synchronizers, and CDC <strong>timing constraints<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Are Two Clocks from the Same MMCM Synchronous or Asynchronous?<\/strong><\/p>\n\n\n\n<p>If both clocks are generated by the <strong>same MMCM<\/strong>, then:<\/p>\n\n\n\n<p><strong>They are synchronous<\/strong>, in the sense that they are <strong>frequency-locked<\/strong> and <strong>have a known phase relationship<\/strong> (even if they don\u2019t have the same frequency).<\/p>\n\n\n\n<p><strong>What Makes Them Synchronous?<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Same clock source (MMCM input)<\/strong><\/li>\n\n\n\n<li><strong>Known divider\/multiplier ratios<\/strong><\/li>\n\n\n\n<li><strong>Toolchain (Vivado) understands their relationship<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Even if the output clocks are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>100 MHz (CLK_OUT1)<\/li>\n\n\n\n<li>66.667 MHz (CLK_OUT2)<\/li>\n<\/ul>\n\n\n\n<p>\u2026as long as they&#8217;re derived from the <strong>same input and MMCM instance<\/strong>, they <strong>do not drift<\/strong> apart over time. Their <strong>edges may not align often<\/strong>, but their <strong>relationship is deterministic<\/strong> and repeatable.<\/p>\n\n\n\n<p>This makes them <strong>synchronous but not edge aligned<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Final Thought<\/strong><\/p>\n\n\n\n<p>CDC errors are subtle, dangerous, and hard to debug. If you see inter-clock violations in Vivado\u2019s timing report, it usually means <strong>you haven\u2019t handled CDC properly<\/strong>. <\/p>\n\n\n\n<p>Worse \u2014 if you see no violations but have unsafe crossings, you\u2019ve created a <strong>ticking time bomb<\/strong>.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In digital design, particularly in FPGA development, managing signal transfers across different clock domains is critical. Failure to handle Clock Domain Crossing (CDC) correctly can lead to elusive, non-reproducible bugs that are nearly impossible to debug in post-silicon. This blog post explores the fundamentals of clock domains, when clocks are considered asynchronous, and why CDC &hellip;<br \/><a href=\"https:\/\/blog.edgesmart.co.uk\/index.php\/2025\/07\/26\/cdc-101-1-clock-domains-cdc-safety\/\" class=\"more-link pen_button pen_element_default pen_icon_arrow_double\">Continue reading <span class=\"screen-reader-text\">CDC-101.1 Fundamentals of Clock Domain(s)<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-314","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/314","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/comments?post=314"}],"version-history":[{"count":15,"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/314\/revisions"}],"predecessor-version":[{"id":338,"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/314\/revisions\/338"}],"wp:attachment":[{"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/media?parent=314"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/categories?post=314"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.edgesmart.co.uk\/index.php\/wp-json\/wp\/v2\/tags?post=314"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}