c - menstruation - smiley




Was bedeutet((Port*) 0x41004400UL) hier? (2)

Ich arbeite an einem Entwicklungsboard, das einen 32-Bit-ARM-basierten Mikroregler hat (nämlich das Board Atmel SAM D21J18A). Ich bin immer noch in der Lernphase und ich habe noch viel zu tun, aber ich bin wirklich auf Embedded-Systeme.

Ich habe einige Hintergrundinformationen in C. Es ist jedoch offensichtlich nicht genug. Ich habe mir die Codes eines Beispielprojekts von Atmel angesehen und ich habe nicht wirklich einige Teile davon bekommen. Hier ist einer von ihnen:

    #define PORT              ((Port     *)0x41004400UL) /**< \brief (PORT) APB Base Address */

Port ist definiert als:

    typedef struct {
        PortGroup             Group[2];    /**< \brief Offset: 0x00 PortGroup groups [GROUPS] */
    } Port;

und PortGroup ist definiert als:

typedef struct {
    __IO PORT_DIR_Type             DIR;         /**< \brief Offset: 0x00 (R/W 32) Data Direction */
    __IO PORT_DIRCLR_Type          DIRCLR;      /**< \brief Offset: 0x04 (R/W 32) Data Direction Clear */
    __IO PORT_DIRSET_Type          DIRSET;      /**< \brief Offset: 0x08 (R/W 32) Data Direction Set */
    __IO PORT_DIRTGL_Type          DIRTGL;      /**< \brief Offset: 0x0C (R/W 32) Data Direction Toggle */
    __IO PORT_OUT_Type             OUT;         /**< \brief Offset: 0x10 (R/W 32) Data Output Value */
    __IO PORT_OUTCLR_Type          OUTCLR;      /**< \brief Offset: 0x14 (R/W 32) Data Output Value Clear */
    __IO PORT_OUTSET_Type          OUTSET;      /**< \brief Offset: 0x18 (R/W 32) Data Output Value Set */
    __IO PORT_OUTTGL_Type          OUTTGL;      /**< \brief Offset: 0x1C (R/W 32) Data Output Value Toggle */
    __I  PORT_IN_Type              IN;          /**< \brief Offset: 0x20 (R/  32) Data Input Value */
    __IO PORT_CTRL_Type            CTRL;        /**< \brief Offset: 0x24 (R/W 32) Control */
    __O  PORT_WRCONFIG_Type        WRCONFIG;    /**< \brief Offset: 0x28 ( /W 32) Write Configuration */
    RoReg8                         Reserved1[0x4];
    __IO PORT_PMUX_Type            PMUX[16];    /**< \brief Offset: 0x30 (R/W  8) Peripheral Multiplexing n */
    __IO PORT_PINCFG_Type          PINCFG[32];  /**< \brief Offset: 0x40 (R/W  8) Pin Configuration n */
    RoReg8                         Reserved2[0x20];
} PortGroup;

Also, hier sehen wir uns die Adresse 0x41004400UL an, holen die Daten rein und was passiert dann?

Ich habe nachgesehen, konnte aber nichts Nützliches finden. Wenn Sie irgendwelche Vorschläge (Tutorials, Bücher etc.) haben, lassen Sie mich bitte hören.


Im Allgemeinen können Sie auf diese Weise auf ein Hardware-Register in C zugreifen:

#define PORT  (*(volatile uint8_t*)0x1234)
  • 0x1234 ist die Registeradresse
  • uint8_t ist der Typ des Registers, in diesem Fall 1 Byte groß.
  • volatile ist erforderlich, damit der Compiler weiß, dass er eine solche Variable nicht optimieren kann, sondern dass jeder Lese- oder Schreibzugriff auf die im Code angegebene Variable tatsächlich ausgeführt werden muss.
  • (volatile uint8_t*) das Integer-Literal in eine Adresse des gewünschten Typs um.
  • Die linken * nehmen dann den Inhalt dieser Adresse, so dass das Makro genauso verwendet werden kann, als ob PORT eine reguläre Variable wäre.

Beachten Sie, dass dies nichts zuweist! Es wird nur angenommen, dass an der angegebenen Adresse ein Hardware-Register vorhanden ist, auf das der angegebene Typ ( uint8_t ) uint8_t .

Mit der gleichen Methode können Sie auch andere C-Datentypen verwenden, um Hardware-Registern direkt zu entsprechen. Beispielsweise können Sie mit einer handlichen Struktur den gesamten Registerbereich eines bestimmten Hardware-Peripheriegeräts abbilden. Solch ein Code ist jedoch ein bisschen gefährlich und fragwürdig, da er Dinge wie Ausrichtung / Strukturauffüllung und Aliasing berücksichtigen muss.

Wie für den spezifischen Code in Ihrem Beispiel ist es eine typische schreckliche Registerkarte für ein bestimmtes Hardware-Peripheriegerät (sieht wie ein einfacher Allzweck-I / O-Port aus) auf einem bestimmten Mikrocontroller. Ein solches Biest wird typischerweise mit jedem Compiler bereitgestellt, der die MCU unterstützt.

Solche Registerkarten sind leider immer auf schreckliche, komplett nicht portable Art geschrieben. Zum Beispiel sind zwei Unterstriche __ in C ein verbotener Bezeichner. Weder der Compiler noch der Programmierer dürfen solche Bezeichner deklarieren (7.1.3).

Was wirklich merkwürdig ist, ist, dass sie das volatile Schlüsselwort weggelassen haben. Dies bedeutet, dass Sie eines dieser Szenarien hier haben:

  • Das flüchtige Schlüsselwort ist unter der Port Definition verborgen. Höchstwahrscheinlich ist dies der Fall oder
  • Die Registerkarte ist voller fataler Fehler oder
  • Der Compiler ist so ein schrecklicher Mist, dass er Variablen überhaupt nicht optimiert. Was würde die Probleme mit volatile verschwinden lassen.

Ich würde das weiter untersuchen.

Was das Auffüllen von Strukturen und das Aliasing betrifft, so hat der Compiler-Anbieter wahrscheinlich implizit angenommen, dass nur sein Compiler verwendet werden soll. Sie haben kein Interesse daran, Ihnen eine portable Registerkarte zu liefern, so dass Sie den Compiler des Konkurrenten für die gleiche MCU wechseln können.


Nichts passiert, weil Sie nur einige Deklarationen präsentieren. Ich bin mir nicht ganz sicher, was die Frage eigentlich ist, aber um diesen Code kurz zu erklären:

  • 0x41004400UL ist offensichtlich eine Adresse im I / O-Bereich (nicht im regulären Speicher), wo ein Port startet (ein Satz von I / O-Registern)

  • Dieser Port besteht aus zwei Gruppen mit einer ähnlichen Anordnung von einzelnen Registern

  • struct PortGroup modelliert diese Register genau in dem auf der Hardware vorhandenen Layout

Um die Bedeutung der Register zu kennen, sehen Sie sich die Hardware-Dokumentation an.







atmelstudio