SAM3X8E (Arduino Due) Registri pin IO


9

Come funzionano i registri IO di Arduino Due? Su Arduino Uno è sufficiente impostare DDRx, poi PINxa leggere, PORTxa scrivere, mi piacerebbe fare la stessa cosa con un Arduino Due, ma ha molti più registri, come PIO_OWER, PIO_OSER, PIO_CODR, PIO_SODR, ecc trovo corrispondenza tra Arduino Uno e Registri di Arduino Due.

Ci sono anche alcune funzioni utili come pio_clear, pio_set, pio_gete altri, tutti spiegati qui:

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

Ora, penso di aver capito cosa fanno le tre funzioni menzionate, ma non altre, per esempio:

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

Non riesco a capire cosa ul_attributee cosa ul_typesono.


Ecco una classe GPIO implementata per AVR e SAM. Potrebbe dare un suggerimento su come utilizzare i registri: github.com/mikaelpatel/Arduino-GPIO/blob/master/src/Hardware/…
Mikael Patel

Risposte:


7

Se hai letto la sezione 31 della scheda tecnica, disponibile da qui , le cose potrebbero essere un po 'più chiare per te.

Ecco un riassunto di ciò che so:

PIO è l'acronimo di Parallel Input / Output e offre la funzionalità per leggere e scrivere più porte di registro alla volta. Laddove il foglio dati menziona un registro, ad esempio PIO_OWER, la libreria Arduino ha macro per accedervi in ​​questo formato REG_PIO? _OWER dove? è A, B, C o D per le diverse porte disponibili.

Tendo ancora a usare la funzione pinMode () di Arduino lenta per impostare input / output sui pin in quanto rende il codice più leggibile rispetto alle chiamate di registri basate su acronimo come REG_PIOC_OWER = 0xdeadbeef, ma quindi uso i registri diretti per impostare i pin per prestazioni / sincronizzazione. Finora non ho fatto nulla con l'input, quindi i miei esempi sono tutti basati sull'output.

Per un utilizzo di base, utilizzare REG_PIO? _SODR per impostare le linee di uscita alte e REG_PIO? _CODR per impostarle su basse. Ad esempio REG_PIOC_SODR = 0x00000002 imposterebbe il bit 1 (numerato da zero) su PORTC (questo è il pin 33 del Due digitale) alto. Tutti gli altri pin su PORTC rimangono invariati. REG_POIC_CODR = 0x00000002 imposterà il bit 1 su PORTC basso. Ancora una volta tutti gli altri pin rimarrebbero invariati.

Poiché ciò non è ancora ottimale o sincronizzato se si lavora con dati paralleli, esiste un registro che consente di scrivere tutti i 32 bit di una porta con una sola chiamata. Questi sono REG_PIO? _ODSR, quindi REG_PIOC_ODSR = 0x00000002 ora imposterebbe il bit 1 su PORTC alto e tutti gli altri bit su PORTC verrebbero impostati immediatamente su basso in una singola istruzione CPU.

Poiché è improbabile che ti trovi mai in una situazione in cui è necessario impostare contemporaneamente tutti e 32 i bit di una porta, è necessario memorizzare il valore corrente dei pin, eseguire un'operazione AND per mascherare quelli vuoi modificare, eseguire un'operazione OR per impostare quelli che desideri impostare alto, quindi eseguire la scrittura e di nuovo, e questo non è ottimale. Per ovviare a questo, la CPU stessa eseguirà il mascheramento per te. Esiste un registro chiamato OWSR (registro dello stato di scrittura dell'output) che maschererà tutti i bit che si scrivono negli ODSR che non corrispondono ai bit impostati nell'OWSR.

Quindi, ora se chiamiamo REG_PIOC_OWER = 0x00000002 (questo imposta il bit 1 del valore OWSR alto) e REG_PIOC_OWDR = 0xfffffffd (questo cancella tutti i bit tranne il bit 1 del OWSR) e quindi chiama nuovamente REG_PIOC_ODSR = 0x00000002, questa volta cambierebbe solo il bit 1 di PORTC e tutti gli altri bit rimangono invariati. Prestare attenzione al fatto che OWER abilita tutti i bit impostati su 1 nel valore scritto e che OWDR disabilita tutti i bit impostati su 1 nel valore scritto. Anche se l'ho capito quando l'ho letto, sono comunque riuscito a fare un errore di codice quando scrivevo il mio primo codice di prova pensando che OWDR disabilitasse i bit che non erano impostati su 1 nel valore che ho scritto.

Spero che questo ti abbia almeno dato un po 'di vantaggio nella comprensione del PIO della CPU Due. Buona lettura e ascolto e se hai ulteriori domande, proverò a rispondere.

Modifica: un'altra cosa ...

Come fai a sapere quali bit dei PORT corrispondono a quali linee digitali dei Due? Dai un'occhiata: Due Pinout


3

Esiste un'equivalenza abbastanza semplice per l'accesso diretto diretto ai pin. Di seguito è riportato un codice di esempio che mostra come impostare un pin digitale alto e poi basso. Il primo è per un Arduino Due, il secondo è per 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

Tutto ciò che è necessario per farlo dovrebbe essere incluso di default - e in caso contrario #include <Arduino.h>dovrebbe essere sufficiente per arrivarci.

In realtà ci sono funzioni disponibili che possono essere richiamate una volta che si ha il Piopuntatore per eseguire l'impostazione / cancellazione / resistori pullup / ecc. utilizzando chiamate di funzione dall'aspetto leggermente più pulito. Un elenco completo è disponibile in file di intestazione.


0

Questo è un esempio di codice che fa lampeggiare un led sul pin 33. Codice preso in prestito dall'alto - molte grazie per le spiegazioni molto utili :) Questo è l'inizio di un progetto per parlare con un display touchscreen TFT con dumping di dati a pixel a colori a 16 bit che necessita accesso rapido alle porte. Penso di avere il codice giusto, in particolare la linea che imposta il pin in basso. Il led lampeggia felicemente.

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);   
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.