Registros de Pin IO do SAM3X8E (devido a Arduino)

9

Como os registros de entrada / saída do Arduino Due funcionam? Em Arduino Uno apenas definir DDRx, em seguida, PINxa ler, PORTxa escrever, eu gostaria de fazer a mesma coisa com um Arduino Due, mas tem muitos mais registos, como PIO_OWER, PIO_OSER, PIO_CODR, PIO_SODR, etc. Eu não encontro nenhuma correspondência entre Arduino Uno e Registros do Arduino Due.

Há também algumas funções úteis, tais como pio_clear, pio_set, pio_get, e outros, tudo explicado aqui:

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

Agora, acho que entendi o que as três funções mencionadas fazem, mas não outras, por exemplo:

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

Não consigo descobrir o que é ul_attributee o que ul_typeé.

Alex
fonte
Aqui está uma classe GPIO implementada para AVR e SAM. Pode dar uma dica de como usar os registros: github.com/mikaelpatel/Arduino-GPIO/blob/master/src/Hardware/...
Mikael Patel

Respostas:

7

Se você leu a seção 31 da Folha de dados, disponível aqui , as coisas podem ficar um pouco mais claras para você.

Aqui está um resumo do que eu sei:

PIO significa Entrada / Saída Paralela e oferece a funcionalidade de ler e gravar várias portas de registro por vez. Onde a folha de dados menciona um registro, por exemplo, PIO_OWER, a biblioteca do Arduino possui macros para acessá-las neste formato REG_PIO? _OWER onde? é A, B, C ou D para as diferentes portas disponíveis.

Eu ainda uso a lenta função pinMode () do Arduino para definir entrada / saída nos pinos, pois torna o código mais legível do que as chamadas baseadas em acrônimos, como REG_PIOC_OWER = 0xdeadbeef, mas depois use os registradores diretos para definir os pinos para os pinos. desempenho / sincronização. Até o momento, ainda não fiz nada com a entrada, portanto meus exemplos são todos baseados em saída.

Para uso básico, você usaria REG_PIO? _SODR para definir linhas de saída altas e REG_PIO? _CODR para defini-las baixas. Por exemplo, REG_PIOC_SODR = 0x00000002 definiria o bit 1 (numerado de zero) em PORTC (este é o pino digital devido 33) alto. Todos os outros pinos no PORTC permanecem inalterados. REG_POIC_CODR = 0x00000002 definiria o bit 1 em PORTC baixo. Novamente, todos os outros pinos permaneceriam inalterados.

Como isso ainda não é o ideal, ou sincronizado se você estiver trabalhando com dados paralelos, existe um registro que permite gravar todos os 32 bits de uma porta com uma única chamada. Esses são os REG_PIO? _ODSR, portanto REG_PIOC_ODSR = 0x00000002 agora definiria o bit 1 em PORTC alto e todos os outros bits em PORTC seriam baixos instantaneamente em uma única instrução da CPU.

Como é improvável que você esteja em uma situação em que precisa definir todos os 32 bits de uma porta ao mesmo tempo, será necessário armazenar o valor atual dos pinos, executar uma operação AND para mascarar os que deseja alterar, execute uma operação OR para definir os que você deseja definir como altos, depois execute sua gravação novamente e isso não é o ideal. Para superar isso, a própria CPU executará o mascaramento para você. Há um registro chamado OWSR (registro de status de gravação de saída) que mascara os bits que você grava nos ODSRs que não correspondem aos bits definidos no OWSR.

Portanto, agora, se chamarmos REG_PIOC_OWER = 0x00000002 (isso define o bit 1 do OWSR alto) e REG_PIOC_OWDR = 0xfffffffd (isso limpa todos os bits, exceto o bit 1 do OWSR) e, em seguida, chamamos REG_PIOC_ODSR = 0x00000002 novamente, desta vez apenas alteraria o bit 1 de PORTC e todos os outros bits permanecem inalterados. Preste atenção ao fato de que OWER habilita todos os bits definidos como 1 no valor que você escreve e que OWDR desativa todos os bits definidos como 1 no valor que você escreve. Embora tenha entendido isso quando o li, ainda consegui cometer um erro de código ao escrever meu primeiro código de teste, pensando que o OWDR desabilitou os bits que não estavam definidos como 1 no valor que escrevi.

Espero que isso tenha pelo menos um começo para você entender o PIO do CPU devido. Faça uma leitura e uma peça de teatro e, se tiver mais perguntas, tentarei respondê-las.

Edit: Mais uma coisa ...

Como você sabe quais bits dos PORTs correspondem a quais linhas digitais do Due? Confira: Due Pinout

Mick Waites
fonte
3

Existe uma equivalência bastante simples para o acesso direto direto aos pinos. Abaixo está um código de exemplo que mostra como definir um pino digital alto e baixo. O primeiro é para um Arduino Due, o segundo é para o 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

Tudo o que é necessário para fazer isso deve ser incluído por padrão - e, caso contrário, #include <Arduino.h>deve ser suficiente para chegar lá.

Na verdade, existem funções disponíveis que podem ser chamadas depois que você tiver o Pioponteiro para ajustar / limpar / resistores pullup / etc. usando chamadas de função com aparência um pouco mais limpa. Uma lista completa pode ser encontrada no arquivo de cabeçalho.

Tom Carpenter
fonte
0

Este é um exemplo de código que pisca um led no pino 33. Código emprestado de cima - muito obrigado pelas explicações muito úteis :) Este é o começo de um projeto para conversar com uma tela touchscreen TFT com despejo de dados de pixel colorido de 16 bits que precisa acesso rápido às portas. Eu acho que tenho o código certo - particularmente a linha que define o pino baixo. O led está piscando alegremente.

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);   
}
James Moxham
fonte