SAM3X8E (Arduino Due) Pin-E / A-Register


9

Wie funktionieren die IO-Register von Arduino Due? Auf Arduino Uno setzt nur DDRxdann PINxzu lesen, PORTxzu schreiben, würde ich das Gleiche mit einem Arduino Due zu tun, aber es hat viele weiteren Register, zB PIO_OWER, PIO_OSER, PIO_CODR, PIO_SODR, etc. Ich finde keine Übereinstimmung zwischen Arduino Uno und Arduino Due Register.

Es gibt auch einige nützliche Funktionen wie pio_clear, pio_set, pio_getund andere, alle hier erklärt:

http://asf.atmel.com/docs/3.19.0/sam3x/html/group__sam__drivers__pio__group.html

Jetzt denke ich, ich habe verstanden, was die drei genannten Funktionen tun, aber nicht andere, zum Beispiel:

pio_configure (Pio *p_pio, const pio_type_t ul_type, const uint32_t ul_mask, const uint32_t ul_attribute)

Ich kann nicht herausfinden was ul_attributeund ul_typesind.


Hier ist eine GPIO-Klasse, die für AVR und SAM implementiert ist. Könnte einen Hinweis geben, wie man die Register verwendet: github.com/mikaelpatel/Arduino-GPIO/blob/master/src/Hardware/…
Mikael Patel

Antworten:


7

Wenn Sie Abschnitt 31 des Datenblatts gelesen haben, der hier verfügbar ist , werden die Dinge für Sie möglicherweise etwas klarer.

Hier ist eine Zusammenfassung dessen, was ich weiß:

PIO steht für Parallel Input / Output und bietet die Funktionalität, mehrere Registerports gleichzeitig zu lesen und zu schreiben. Wenn im Datenblatt ein Register erwähnt wird, z. B. PIO_OWER, verfügt die Arduino-Bibliothek über Makros für den Zugriff in diesem Format. REG_PIO? _OWER where? ist entweder A, B, C oder D für die verschiedenen verfügbaren Ports.

Ich neige dazu, immer noch die langsame Arduino pinMode () -Funktion zu verwenden, um die Ein- / Ausgabe auf den Pins festzulegen, da sie den Code lesbarer macht als die auf Akronymen basierenden Registeraufrufe wie REG_PIOC_OWER = 0xdeadbeef, aber dann die direkten Register zum Setzen der Pins für Leistung / Synchronisation. Bis jetzt habe ich noch nichts mit Eingabe gemacht, daher basieren meine Beispiele alle auf Ausgabe.

Für die grundlegende Verwendung würden Sie REG_PIO? _SODR verwenden, um die Ausgangsleitungen hoch und REG_PIO? _CODR, um sie niedrig zu setzen. Zum Beispiel würde REG_PIOC_SODR = 0x00000002 Bit 1 (von Null nummeriert) auf PORTC (dies ist Due Digital Pin 33) hoch setzen. Alle anderen Pins auf PORTC bleiben unverändert. REG_POIC_CODR = 0x00000002 würde Bit 1 auf PORTC niedrig setzen. Auch hier wären alle anderen Stifte unverändert.

Da dies immer noch nicht optimal ist oder synchronisiert wird, wenn Sie mit parallelen Daten arbeiten, gibt es ein Register, mit dem Sie alle 32 Bits eines Ports mit einem einzigen Aufruf schreiben können. Dies sind die REG_PIO? _ODSR, also würde REG_PIOC_ODSR = 0x00000002 jetzt Bit 1 auf PORTC hoch setzen und alle anderen Bits auf PORTC würden sofort in einem einzelnen CPU-Befehl auf niedrig gesetzt.

Da es unwahrscheinlich ist, dass Sie jemals in einer Situation sind, in der Sie alle 32 Bits eines Ports gleichzeitig setzen müssen, müssen Sie den aktuellen Wert der Pins speichern und eine UND-Operation ausführen, um die von Ihnen ausgeblendeten Pins auszublenden Wenn Sie Änderungen vornehmen möchten, führen Sie eine ODER-Verknüpfung aus, um diejenigen festzulegen, die hoch eingestellt werden sollen. Führen Sie dann das Schreiben und erneut aus. Dies ist nicht optimal. Um dies zu überwinden, führt die CPU selbst die Maskierung für Sie durch. Es gibt ein Register namens OWSR (Output Write Status Register), das alle Bits maskiert, die Sie in ODSRs schreiben, die nicht mit den im OWSR festgelegten Bits übereinstimmen.

Wenn wir nun REG_PIOC_OWER = 0x00000002 (dies setzt Bit 1 des OWSR hoch) und REG_PIOC_OWDR = 0xfffffffd (dies löscht alle Bits außer Bit 1 des OWSR) aufrufen und dann REG_PIOC_ODSR = 0x00000002 erneut aufrufen, ändert sich diesmal nur das Bit 1 von PORTC und alle anderen Bits bleiben unverändert. Achten Sie auf die Tatsache , dass OWER ermöglicht alle Bits , die auf 1 gesetzt sind , in dem Wert , den Sie schreiben und dass OWDR deaktiviert alle Bits , die auf 1 gesetzt sind , in dem Wert , den Sie schreiben. Obwohl ich dies beim Lesen verstanden habe, konnte ich beim Schreiben meines ersten Testcodes immer noch einen Codefehler machen, da ich dachte, OWDR habe Bits deaktiviert, die in dem von mir geschriebenen Wert nicht auf 1 gesetzt waren .

Ich hoffe, dies hat Ihnen zumindest einen kleinen Einblick in das Verständnis des PIO der fälligen CPU gegeben. Lesen und spielen Sie und wenn Sie weitere Fragen haben, werde ich versuchen, diese zu beantworten.

Edit: Noch eine Sache ...

Woher wissen Sie, welche Bits der PORTs welchen digitalen Leitungen des Due entsprechen? Überprüfen Sie dies: Due Pinout


3

Es gibt eine ziemlich einfache Äquivalenz für den grundlegenden direkten Pin-Zugriff. Im Folgenden finden Sie einen Beispielcode, der zeigt, wie ein digitaler Pin hoch und dann niedrig eingestellt wird. Der erste ist für einen Arduino Due, der zweite ist für den Arduino Uno / Mega / etc.

const unsigned int imThePin = 10; //e.g. digital Pin 10

#ifdef _LIB_SAM_

    //First lets get the pin and bit mask - this can be done once at the start and then used later in the code (as long as the variables are in scope
    Pio* imThePort = g_APinDescription[imThePin].pPort; 
    unsigned int imTheMask = g_APinDescription[imThePin].ulPin; 

    //Lets set the pin high
    imThePort->PIO_SODR = imTheMask;
    //And then low
    imThePort->PIO_CODR = imTheMask;

#else

    //First lets get the pin and bit mask - this can be done once at the start and then used later in the code (as long as the variables are in scope
    volatile unsigned char* imThePort = portOutputRegister(digitalPinToPort(imThePin)); 
    unsigned char imTheMask = digitalPinToBitMask(imThePin);

    //Lets set the pin high
    *imThePort |= imTheMask;
    //Now low
    *imThePort &= ~imTheMask;

#endif

Alles, was dazu benötigt wird, sollte standardmäßig enthalten sein - und wenn nicht, #include <Arduino.h>sollte es ausreichen, um es dorthin zu bringen.

Es sind tatsächlich Funktionen verfügbar, die aufgerufen werden können, sobald Sie den PioZeiger für die Einstellung / Löschung / Pullup-Widerstände / etc. Haben. mit etwas sauberer aussehenden Funktionsaufrufen. Eine vollständige Liste finden Sie in der Header-Datei.


0

Dies ist ein Codebeispiel, bei dem eine LED an Pin 33 blinkt. Von oben entliehener Code - vielen Dank für die sehr hilfreichen Erklärungen :) Dies ist der Beginn eines Projekts, um mit einem TFT-Touchscreen-Display mit Speicherauszug von 16-Bit-Farbpixeldaten zu sprechen, die benötigt werden schneller Zugriff auf die Ports. Ich glaube, ich habe den richtigen Code - insbesondere die Zeile, die den Pin niedrig setzt. Die LED blinkt glücklich.

void setup() 
{
  pinMode(33, OUTPUT); 
  REG_PIOC_OWER = 0x00000002; 
  REG_PIOC_OWDR = 0xfffffffd; 
}

void loop() 
{
  REG_PIOC_ODSR = 0x00000002; 
  delay(1000);             
  REG_PIOC_ODSR = 0x00000000;    
  delay(1000);   
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.