Das Setzen oder Löschen einer beliebigen Kombination von Bits in einem E / A-Port (sogar das Setzen einiger und das Löschen anderer) sollte höchstens drei Anweisungen erfordern. Bei Wiederholung sollten solche Anweisungen jeweils eine Anweisung enthalten. Leider scheinen viele Anbieter (darunter auch ST) dazu zu neigen, E / A-Bibliotheken zu definieren, die selbst für allgemeine Vorgänge wie diesen Unterprogrammaufrufe generieren.
Ich würde vorschlagen, eigene Methoden zum Festlegen und Löschen von E / A zu definieren. O-Bits und enthalten den Code für diese Methoden, der mit einem __inline
-Qualifikator gekennzeichnet ist, in Ihrer .h-Datei [im Gegensatz zum bloßen Einfügen eines Prototyps in die .h und des Methodencodes in einem separaten Code. c-Datei].
Wenn Sie sich in einer .h-Datei befinden, schreiben Sie:
__inline void SetPorts (GPIO_TypeDef * Addr, uint16_t data) {* Addr = data; } __ inline void ClearPorts (GPIO_TypeDef * Addr, uint16_t Daten) {* Addr = Daten; }
Dann der Code:
setPorts (GPIOA, 1); clearPorts (GPIOA, 2); clearPorts (GPIOA, 1);
wird wahrscheinlich etwas erzeugen (ich bin mir einiger Details nicht sicher):
ldr r0, = GPIOA mov r1, # 1 strh r1, [r0 + 20] mov r2, # 2 strh r2, [r0 + 22] strh r1, [r0 + 22]
Wenn man dagegen den Code GPIO_WriteBit
verwendet würde am Ende eher wie folgt aussehen:
ldr r0, = GPIOA mov r1, # 1 mov r2, # 1 bl _GPIO_WriteBit ldr r0, = GPIOA mov r1, # 2 mov r2, # 0 bl _GPIO_WriteBit ldr r0, = GPIOA mov r1, # 2 mov r2, # 0 bl _GPIO_WriteBit_GPIO_WriteBit :; Der folgende Code setzt eine ziemlich gute Compileroptimierung voraus: cmp r2, # 0 itteq streq r1, [r0 + 20] strne r1, [r0 + 22] bx lr
Im ersten Beispiel werden insgesamt sechs Anweisungen für alle drei Operationen ausgeführt. Im zweiten Beispiel werden zwölf im Hauptcode einmal und ungefähr vier Anweisungen in der WriteBits-Funktion dreimal ausgeführt, was insgesamt 24 ergibt [übersprungene Anweisungen verlängern manchmal die Ausführungszeit und manchmal nicht]. Normalerweise besteht der Zweck des Aufrufs von Unterroutinen darin, die Codegröße gegen die Ausführungsgeschwindigkeit auszutauschen. In diesem Fall ist der Aufruf der Unterroutine jedoch sowohl räumlich als auch zeitlich eine Katastrophe. Die einzige nützliche Arbeit, die durch die Anweisung geleistet wird, ist ein einzelner Geschäftsvorgang. Der Code wird wahrscheinlich die Register r0-r2 ungestört lassen, aber der aufrufende Code kann das nicht wissen. Folglich müssen alle drei Parameter vor jedem Methodenaufruf explizit festgelegt werden.
Ich weiß nicht, warum Chiphersteller Methoden definieren, die GPIO-Bits schreiben, sich aber nicht die Mühe machen, sie inline zu machen, aber ich würde vorschlagen In den meisten Fällen sollte man vermeiden, vom Chip-Anbieter bereitgestellte Funktionen zum Schreiben von GPIO-Ports zu verwenden, wenn man sich um die Effizienz kümmert.
Übrigens bin ich generell eher skeptisch gegenüber vom Hersteller bereitgestellten E / A-Funktionen im Allgemeinen. Während sie manchmal einen Programmierer mit einem höheren Abstraktionsgrad als die Rohhardware präsentieren können, was nützlich ist, machen sie Code in vielen Fällen schwieriger zu schreiben, schwerer zu lesen und weniger effizient. Sie können auch manchmal unerwünschte Nebenwirkungen haben, die an anderer Stelle Probleme verursachen können. Wenn für ein Peripheriegerät beispielsweise eine Uhr auf einen von zwei Modi eingestellt werden muss und im Allgemeinen mit einem dieser Modi besser funktioniert, kann eine vom Hersteller bereitgestellte Bibliothek für das Peripheriegerät die Uhr auf den "besseren" Modus konfigurieren, selbst wenn diese Uhr aktiviert ist mit einem anderen Peripheriegerät geteilt, das es benötigt, um in dem anderen zu sein. Wenn Peripheriegeräte Ressourcen gemeinsam nutzen (wie dies häufig der Fall ist), ist es möglicherweise unmöglich, die Bibliotheken ordnungsgemäß zu verwenden, ohne den gesamten darin enthaltenen Code zu lesen und zu verstehen. Wenn der gesamte Zweck der Bibliothek darin bestand, ein paar Registerschreibvorgänge zu speichern, sind die Konsequenzen eines Bibliotheksaufrufs möglicherweise viel schwieriger herauszufinden als die Konsequenzen des Codes, den sie ersetzt.