Registres E / S SAM3X8E (Arduino Due)


9

Comment fonctionnent les registres d'E / S d'Arduino Due? Sur Arduino Uno vient de mettre DDRx, puis PINxde lire, PORTxd'écrire, je voudrais faire la même chose avec un Arduino Due, mais il a beaucoup plus de registres, tels que PIO_OWER, PIO_OSER, PIO_CODR, PIO_SODR, etc. Je ne trouve aucune correspondance entre Arduino Uno et Registres Arduino Due.

Il y a aussi quelques fonctions utiles telles que pio_clear, pio_set, pio_getet d' autres, tous expliqués ici:

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

Maintenant, je pense avoir compris ce que font les trois fonctions mentionnées, mais pas les autres, par exemple:

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

Je ne peux pas comprendre ce ul_attributeque ul_typesont et


Voici une classe GPIO implémentée pour AVR et SAM. Pourrait donner un aperçu de la façon d'utiliser les registres: github.com/mikaelpatel/Arduino-GPIO/blob/master/src/Hardware/…
Mikael Patel

Réponses:


7

Si vous avez lu la section 31 de la fiche technique, disponible à partir d' ici , les choses peuvent devenir un peu plus claires pour vous.

Voici un résumé de ce que je sais:

PIO signifie Parallel Input / Output et offre la fonctionnalité de lecture et d'écriture de plusieurs ports de registre à la fois. Lorsque la fiche technique mentionne un registre, par exemple PIO_OWER, la bibliothèque Arduino a des macros pour y accéder dans ce format REG_PIO? _OWER où? est soit A, B, C ou D pour les différents ports disponibles.

J'ai tendance à toujours utiliser la fonction lente Arduino pinMode () pour définir l'entrée / sortie sur les broches car elle rend le code plus lisible que les appels de registres basés sur l'acronyme tels que REG_PIOC_OWER = 0xdeadbeef, mais ensuite utiliser les registres directs pour définir les broches pour performances / synchronisation. Pour l'instant, je n'ai rien fait avec l'entrée, donc mes exemples sont tous basés sur la sortie.

Pour une utilisation de base, vous utiliseriez REG_PIO? _SODR pour définir les lignes de sortie à un niveau élevé et REG_PIO? _CODR pour les définir à un niveau bas. Par exemple, REG_PIOC_SODR = 0x00000002 mettrait le bit 1 (numéroté à partir de zéro) sur PORTC (il s'agit de la broche numérique due 33) à la hauteur. Toutes les autres broches sur PORTC restent inchangées. REG_POIC_CODR = 0x00000002 mettrait le bit 1 sur PORTC bas. Encore une fois, toutes les autres broches seraient inchangées.

Comme cela n'est toujours pas optimal ou synchronisé si vous travaillez avec des données parallèles, il existe un registre qui vous permet d'écrire les 32 bits d'un port en un seul appel. Ce sont les REG_PIO? _ODSR, donc REG_PIOC_ODSR = 0x00000002 mettrait maintenant le bit 1 sur PORTC haut et tous les autres bits sur PORTC seraient mis bas immédiatement dans une seule instruction CPU.

Comme il est peu probable que vous vous trouviez dans une situation où vous devez définir les 32 bits d'un port en même temps, vous devez stocker la valeur actuelle des broches, effectuer une opération ET pour masquer celles que vous vous souhaitez modifier, effectuer une opération OU pour définir celles que vous souhaitez définir à un niveau élevé, puis effectuer votre écriture et à nouveau, et ce n'est pas optimal. Pour surmonter cela, le CPU lui-même effectuera le masquage pour vous. Il existe un registre appelé OWSR (registre d'état d'écriture de sortie) qui masquera tous les bits que vous écrivez dans les ODSR qui ne correspondent pas aux bits définis dans le OWSR.

Donc, maintenant, si nous appelons REG_PIOC_OWER = 0x00000002 (cela définit le bit 1 du haut OWSR) et REG_PIOC_OWDR = 0xfffffffd (cela efface tous les bits sauf le bit 1 du OWSR), puis appelons REG_PIOC_ODSR = 0x00000002 à nouveau, cette fois, cela ne changera que le bit 1 de PORTC et tous les autres bits restent inchangés. Faites attention au fait que OWER active tous les bits définis sur 1 dans la valeur que vous écrivez et que OWDR désactive tous les bits définis sur 1 dans la valeur que vous écrivez. Même si j'ai compris cela lorsque je l'ai lu, j'ai quand même réussi à faire une erreur de code lors de l'écriture de mon premier code de test en pensant que OWDR a désactivé les bits qui n'étaient pas définis sur 1 dans la valeur que j'ai écrite.

J'espère que cela vous a au moins donné un peu de départ pour comprendre le PIO du CPU Due. Lisez et jouez et si vous avez d'autres questions, j'essaierai d'y répondre.

Edit: Encore une chose ...

Comment savez-vous quels bits des PORTs correspondent à quelles lignes numériques du Due? Vérifiez ceci: Brochage dû


3

Il existe une équivalence assez simple pour l'accès direct de base aux broches. Vous trouverez ci-dessous un exemple de code qui montre comment définir une broche numérique haute puis basse. Le premier est pour un Arduino Due, le second est pour l'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

Tout ce qui est nécessaire pour le faire doit être inclus par défaut - et sinon il #include <Arduino.h>devrait être suffisant pour y arriver.

Il existe en fait des fonctions disponibles qui peuvent être appelées une fois que vous avez le Piopointeur pour effectuer les résistances de réglage / effacement / pullup / etc. en utilisant des appels de fonction légèrement plus propres. Une liste complète se trouve dans le En tête de fichier.


0

Ceci est un exemple de code qui fait clignoter une led sur la broche 33. Code emprunté d'en haut - merci beaucoup pour les explications très utiles :) C'est le début d'un projet pour parler à un écran tactile TFT avec dumping de données de pixels couleur 16 bits qui nécessite accès rapide aux ports. Je pense que j'ai le bon code - en particulier la ligne qui définit la broche basse. La led clignote joyeusement.

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);   
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.