Réponse Atmega16 inattendue sur UART

8

Réponse Atmega16 inattendue sur UART

Bref résumé du problème

J'ai flashé un Atmega16 avec du code qui devrait entraîner le renvoi par Atmega16 du caractère que je lui envoie via un terminal. J'obtiens une réponse, mais c'est rarement le personnage que j'ai envoyé. Je peux voir la sortie correcte en modifiant le débit en bauds mais je ne comprends pas pourquoi le bon débit en bauds fonctionne.

Plus de détails

J'essaie d'en savoir plus sur la programmation de microprogrammes à mon rythme, car je l'apprécie beaucoup. Jusqu'à présent, dans la programmation du firmware que j'ai faite à uni, nous avons reçu des fichiers de code squelette qui effectuent une grande partie de l'interface périphérique et configurés pour nous, mais je voudrais l'apprendre moi-même. J'ai quelques questions sur ce que je fais ici saupoudré tout au long du post mais je vais les détailler à la fin. Si vous relevez des malentendus ou des lacunes potentielles dans mes connaissances, j'apprécierais grandement toute contribution que vous pourriez avoir.

Le code

Le code que j'ai flashé sur mon Atmega16 est pris presque ligne pour ligne du tutoriel `` Utilisation de l'USART dans AVR-GCC '' sur cette page . Tout ce que j'ai ajouté est le #define pour F_CPU. Le code d'origine n'avait pas de # définition pour F_CPU, donc mon code ne se compilerait pas dans AtmelStudio 7. Quelqu'un pourrait-il expliquer pourquoi l'auteur n'aurait pas défini F_CPU dans son fichier d'origine? Je suppose qu'ils ont peut-être utilisé un autre outil ou compilateur qu'Atmel Studio 7, mais je ne peux pas le dire avec certitude.

#include <avr/io.h>
#define F_CPU 7372800 //this was chosen because the tutorial states this is the frequency we want to operate at
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)

int main ( void )
{
    char ReceivedByte ;
    UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
    UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
    UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
    for (;;) // Loop forever
    {
        while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
        ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
        while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
        UDR = ReceivedByte ; // Echo back the received byte back to the computer
    }
}

La configuration matérielle

Photo de la configuration matérielle

  • MCU: Atmega16;
  • Chaîne d'outils: Atmel Studio 7, clignotant avec AVR dragon;
  • Alimentation: rail 5 V provenant d'une carte de développement fournie par l'université (qui provient de l'ordinateur USB). Condensateur à disque en céramique 100nF utilisé pour le bypass sur les lignes électriques de la maquette
  • Convertisseur USB vers série: celui-ci . TXD sur le convertisseur USB vers série connecté à RXD Atmega (broche 15). RXD sur le convertisseur connecté à RXD sur Atmega (broche 14).
  • Logiciel du terminal: PuTTY (avec un débit en bauds de 9600).

    Preuve des réponses incorrectes

    Pour réitérer, l'Atmega devrait retourner ce qui lui a été envoyé, c'est-à-dire que OUTPUT devrait être exactement la même chose que INPUT.

    Sortie PuTTY

    CONTRIBUTIONPRODUCTIONF&F6z>0espace0X8

    Captures d'oscilloscope

    J'ai utilisé mon Picoscope avec décodage série pour vérifier que l'Atmega reçoit la bonne entrée, ce qui semble être le cas. Par exemple, lorsque j'appuie sur la touche «f», il est correctement reçu. La sortie est toujours un «6» (ou une esperluette «&» à l'occasion).

Capture de portée sur la broche RX de l'Atmega16 montrant que le bon caractère est envoyé via le logiciel du terminal ('f')

Capture de portée sur la broche TX de l'Atmega16 montrant qu'une réponse indésirable est renvoyée ('6')

Une solution sur laquelle je suis tombé et que je ne comprends pas

Si je change la vitesse de transmission en 2500T PuTTY, tout s'affiche correctement. J'ai choisi cette valeur au hasard et je ne sais pas pourquoi cela fonctionne (cela me porte à croire que j'ai fait une erreur quelque part avec le débit en bauds mais je ne vois pas où étant donné j'ai copié le tutoriel presque exactement ... Je pensée).

Des questions

  1. Qu'est-ce que j'ai fait de mal / qu'est-ce qui se passe ici?
  2. Pourquoi le didacticiel d'origine n'est-il pas #define F_CPU?
  3. Pourquoi la définition du débit en bauds à 2500 résout-elle le problème? (Je soupçonne que ce sera répondu si la question 1 est répondue)
daviegravee
la source
2
La simple définition de F_CPU à une certaine valeur ne fait pas fonctionner le micro à cette fréquence. F_CPU devrait être défini comme la fréquence à laquelle vous avez configuré le micro pour fonctionner - mais je ne vois aucune preuve que vous l'avez configuré n'importe où ...
brhans
Question bien écrite. La seule chose qui pourrait l'améliorer serait un schéma.
Blair Fonville
+1 juste pour le LUNETEXtable.
Arsenal
Je remarque que vous n'avez pas de cristal externe sur votre planche à pain. Utilisez-vous l'horloge RC interne? À quelle fréquence prévoyez-vous que le processeur fonctionne?
scotty3785
Grâce à votre discussion sur F_CPU, j'ai fait des recherches et joué et j'ai publié la solution. J'imagine que c'est évident pour vous (comme pour moi maintenant ) mais cela pourrait aider quelqu'un d'autre.
daviegravee

Réponses:

0

Je l'ai compris! Grâce aux commentaires sur F_CPU en réponse à l'OP, j'ai fait quelques recherches (cela pourrait être évident pour vous tous).

Bref résumé de la solution

L'Atmega16 ne fonctionnait pas à la fréquence que je pensais que c'était parce que je ne comprenais pas comment changer la fréquence de son système. En vérifiant les fusibles dans Atmel Studio, j'ai pu voir que je fonctionnais à 2 MHz (ce n'est pas la fréquence d'horloge standard pour autant que je sache, mais je ne vais pas entrer dans le détail ), et pas 7,3728 MHz comme le tutoriel.

F_CPU ne modifie pas la fréquence d'horloge du MCU (l'Atmega16). La fréquence de l'Atmega16 n'a pas été changée à 7,3728 MHz comme cela était nécessaire pour que l'exemple de code fonctionne. Il fonctionnait toujours à la fréquence définie par les fusibles (2 MHz dans ce cas, plus de détails ci-dessous), de sorte que le calcul papier de la vitesse de transmission souhaitée diffère de ce qui a été réellement utilisé.

Code de travail

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 2000000 //THIS LINE IS **NOT** CHANGING THE FREQUENCY OF THE MCU: CHANGE MCU FREQUENCY IN FUSES
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)

int main ( void ){
    char ReceivedByte ;
    UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
    UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
    UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
    for (;;){ // Loop forever
        while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
        ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
        while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
        UDR = ReceivedByte ; // Echo back the received byte back to the computer
    }
}

Plus de détails

Baudrate désiré vs ce que le Atmega était en fait en train de faire

La vitesse de transmission souhaitée (du didacticiel) était de 9600, qui est la vitesse de transmission que j'ai utilisée dans PuTTY. La vitesse de transmission réelle peut être calculée à l'aide de l'équation mise en évidence dans le tableau 60 (page 147) de la fiche technique Atmega16.

Tableau d'équations pour calculer le débit en bauds et l'UBRR à partir de la page 147 Fiche technique Atmega16

Dans l'exemple de code BAUD_PRESCALEest UBRR dans le calcul. BAUD_PRESCALEest évalué à 47 avec les valeurs définies pour F_CPUet USART_BAUDRATE.

BAUD=Fosc16(UBRR+1)
BAUD=2,000,00016(47+1)
BAUD2,604

Et c'était la racine du problème. L'Atmega16 fonctionnait à 2 MHz, ce qui signifiait que la valeur de f_ {osc} était différente de l'exemple du didacticiel, ce qui a entraîné un débit en bauds de 2604 au lieu de 9600.

Notez que f_osc est la fréquence système réelle du MCU, qui n'est pas déterminée par F_CPU.

Cela répond donc également à ma 3ème question: changer la vitesse de transmission à 2500 était heureusement assez proche de la vitesse de fonctionnement de la MCU pour que le terminal puisse interpréter correctement les résultats.

Modification de la fréquence du MCU

Pour changer la fréquence du MCU dans AtmelStudio 7, allez:

Tools > Device programming > Fuses > Change SUT_CKSEL (or LOW.SUT_CKSEL in my case) to desired frequency (make sure you have read up on the side effects of this). 

La fréquence utilisée dans l'exemple n'est pas une fréquence d'horloge interne standard, donc je vais m'en tenir à 2 MHz.

Résumé des réponses à mes propres questions

  1. Qu'est-ce que j'ai fait de mal / qu'est-ce qui se passe ici? Réponse : n'a pas réellement changé la fréquence d'horloge en fréquence d'horloge dans le didacticiel, ce qui a entraîné une vitesse de transmission différente de celle attendue, ce qui a mis le logiciel du terminal (PuTTY) hors de synchronisation avec le MCU
  2. Pourquoi le didacticiel d'origine n'est-il pas #define F_CPU? Réponse : toujours pas tout à fait sûr mais je suppose qu'il est défini dans un makefile non donné dans le tutoriel et que l'auteur n'utilisait pas un IDE comme Atmel Studio
  3. Pourquoi la définition du débit en bauds à 2500 résout-elle le problème? (Je soupçonne que ce sera répondu si la question 1 est répondue) Réponse : Heureusement deviné un nombre proche du débit en bauds de l'Atmega16
daviegravee
la source