L'utilisation de synchroniseurs 2-ff a été une norme pour un signal traversant les limites d'horloge. Et il y a beaucoup de papier / figures illustrant le mécanisme, comme celui-ci:
Il semble que bclk ne puisse échantillonner l'impulsion d' adat qu'une seule fois (au deuxième front montant de bclk ), ce qui entraîne une métastabilité de sortie sur bq1_dat . Comment bq1_dat peut- il être échantillonné "haut" au prochain front d'horloge actif?
En plus de ma question, je voudrais ajouter ce que je pense pour qu'un signal passe en toute sécurité vers un autre domaine d'horloge (supposons que 2-FF soit suffisant pour satisfaire aux exigences MTBF). Veuillez me corriger s'il y a des erreurs.
ps: l'état métastable n'affiche pas la forme d'onde "errante", mais un niveau qui n'est ni "1" ni "0". La figure suivante montre un exemple de sortie métastable.
Le chiffre original provenait des notes de cours pour EE108A, leçon 13: Échec de la métastabilité et de la synchronisation (ow quand les bonnes bascules se détériorent) de WJ Dally.
la source
Réponses:
La réponse simple est qu'ils ne le font pas d'eux-mêmes. Le synchroniseur n'est pas là pour garantir la transmission des données, mais pour vous assurer de ne pas vous retrouver avec des signaux métastables alimentant de nombreux autres signaux et causant des problèmes. Le deuxième FF, comme le montre le diagramme, capture la première sortie FF métastable et l'empêche de se propager davantage dans la conception.
Il existe différentes sortes de signaux, et la manière dont vous incluez les synchroniseurs dépend du signal dont vous parlez. Mais regardons quelques types courants:
Signaux de déclenchement - ou tout signal qui est essentiellement une impulsion qui doit déclencher autre chose. Ceux-ci ne contiennent généralement pas de données, et tout ce qui vous intéresse, c'est qu'il y a, par exemple, un front montant afin de démarrer quelque chose dans un autre domaine d'horloge. Pour les faire passer, vous auriez besoin d'un synchroniseur (faisant essentiellement ce qui est montré dans votre diagramme), mais vous en avez besoin d'un peu plus.
L'option la plus simple consiste à étendre l'impulsion - essentiellement, vous vous assurez que l'impulsion d'entrée est supérieure à 1 période d'horloge de l'horloge de destination (elle devrait être plus longue que 1 cycle d'au moins la plus longue des durées de configuration et de maintien pour le registre de destination) . Par exemple, si vous passez d'une horloge de 20 MHz à une horloge de 15 MHz, vous vous assurerez que votre impulsion est de deux cycles d'horloge à l'entrée, ce qui garantirait qu'elle est présentée à l'horloge de destination et non perdue. Cela répond également à votre question sur la façon dont le signal est garanti de traverser. Si l'impulsion est plus large qu'une période d'horloge de destination, cela signifie que si elle devient métastable sur le premier front d'horloge et finit par être considérée comme un 0, alors sur le deuxième front d'horloge, elle capturera définitivement l'impulsion.
Parce que ce type de signal ne vous intéresse que si l'impulsion a traversé, peu importe si le signal de sortie se termine avec deux cycles d'horloge parfois élevés et un seul cycle le reste. Si vous devez vous assurer qu'il s'agit d'une impulsion à cycle unique, vous pouvez instancier un simple circuit de détection de front.
Bus de contrôle - ou éventuellement types de bus de données. Ceux-ci sont sans doute plus difficiles car si vous avez un flux de données multi-bits qui doit rester synchronisé. Dans ce cas, ce que vous feriez serait d'implémenter quelque chose appelé "handshaking". Vous chargez essentiellement vos données sur l'horloge source et les maintenez. Ensuite, vous envoyez un signal de demande (comme en 1) via un synchroniseur. Une fois le signal de demande traversé, vous savez que le bus de données sera également stabilisé dans le domaine de destination. Vous pouvez ensuite le synchroniser dans une banque de registres de la destination. La destination renvoie ensuite une impulsion d'accusé de réception pour informer la source qu'elle peut charger le mot suivant.
Vous utiliseriez ce type de bus si vous aviez besoin d'envoyer un mot de contrôle à l'horloge de destination pour laquelle vous devez savoir qu'il est arrivé avant d'en envoyer un autre (par exemple, si vous envoyez une commande pour faire quelque chose).
Bus de données - pour les données où vous avez une source qui crache des données en continu ou en rafales, il vaut sans doute mieux utiliser un FIFO que des synchroniseurs. Le FIFO utilise une mémoire à double horloge pour conserver les données, ainsi que des compteurs pour garder une trace de la quantité de données dans le FIFO. Vous écrivez les données dans le FIFO lorsqu'il y a de l'espace, puis incrémentez l'adresse d'écriture. Cette adresse est ensuite généralement codée dans un schéma de "codage gris" qui garantit que chaque incrément d'adresse ne provoque qu'une seulebit dans le bus d'adresse à modifier (ce qui signifie que vous n'avez pas besoin de synchroniser plusieurs bits). Cette adresse est ensuite transférée vers le domaine de destination (via l'une de vos chaînes de synchronisation), où elle est comparée à l'adresse de lecture. S'il y a des données dans le FIFO, elles peuvent ensuite être lues dans la mémoire en utilisant le port d'horloge de destination. L'adresse de lecture est codée en gris de manière similaire et renvoyée à la source via un autre synchroniseur afin que le port d'écriture puisse calculer s'il y a de l'espace dans le FIFO.
Réinitialiser les signaux - ceux-ci utilisent généralement une version modifiée du synchroniseur dans ce qui est connu comme "Assert asynchrone, Désassert synchrone". Dans cette version modifiée, l'entrée de données de la première bascule est liée à GND et le signal de réinitialisation entrant est connecté à la place aux signaux prédéfinis asynchrones de chaque bascule du synchroniseur. Il en résulte un signal de sortie qui est entièrement asynchrone quand il monte haut, mais la chaîne de synchroniseur s'assure qu'il va bas de façon synchrone avec l'horloge de destination en cadencant à travers des zéros dans la chaîne de registre.
Ce type de synchroniseur est terrible pour les données et le contrôle, mais parfaitement adapté pour réinitialiser les signaux. Si toute la logique de destination alimente la sortie de cette chaîne dans les entrées de réinitialisation asynchrone de n'importe quel registre du domaine, alors il n'y a pas de souci de métastabilité lors de l'assertion (même si elle est asynchrone) car tous les registres sont forcés à un état connu. Ensuite, lorsque le signal de réinitialisation est désactivé dans le domaine source, il est désactivé de manière synchrone dans le domaine de destination, ce qui signifie que tous les registres sortent de la réinitialisation sur le même cycle d'horloge (plutôt que +/- 1 cycle s'il s'agissait d'une suppression asynchrone).
Comme vous pouvez le voir ci-dessus, il est beaucoup plus complexe de faire un croisement de domaine d'horloge que de simplement coller un synchroniseur à 2 bascules sur le signal. La méthode exacte utilisée dépend de l'application.
la source
sync_Bits
) pour les FPGA Xilinx et Altera afin d'améliorer le comportement de métastabilité. Le synchroniseur 2-FF est utilisé par exemple danssync_Strobe
pour construire des synchroniseurs plus complexes pour les impulsions.1) En utilisant votre dessin comme exemple, aclk et bclk sont asynchrones l'un à l'autre. En d'autres termes, ils ont différentes sources d'horloge. Ils affichent adat en tant que données valides mais synchronisés uniquement sur aclk. C'est là que le synchroniseur bclk entre en jeu.
2) Ce dessin suppose un scénario du pire des cas, où bq1_dat est une sortie désordonnée parce que le bq1 FF n'a capturé qu'une partie de la fin des données, créant un état métastable sur lequel la sortie est généralement une ordure. Voici l'astuce. Bq2 a le même bclk que bq1, mais il faut 2 cycles d'horloge de bclk pour que les données passent et apparaissent à bq2_dat.
3) Le premier bclk a capturé une partie des données, résultant en une sortie désordonnée, mais le deuxième bclk est un cycle d'horloge plus tard, suffisamment de temps pour que les données ambiguës de bq1_dat se stabilisent dans un état haut ou bas. L'impulsion bq1_dat désordonnée a duré juste assez longtemps pour que bq2 capture un «1» logique valide (niveau logique élevé) et le transmette à bq2_dat en tant que données valides et maintenant synchronisées (niveau logique élevé).
4) En aval, toute horloge utilisant bclk aura des données synchronisées avec lesquelles travailler. Notez que seul le premier bclk FF devait gérer un état métastable . La sortie aurait pu être un niveau logique bas si l'adat avait été juste pico ou nano secondes trop tard. N'oubliez pas que ces bascules échantillonnent les données entrées uniquement sur le front montant de l'horloge. Ce qui se passe avant ou après le front montant est ignoré.
la source