Escrever direto no registrador dos pinos do Arduino

552 views
Skip to first unread message

Alejandro Mesias

unread,
Mar 31, 2014, 7:36:16 AM3/31/14
to hacker...@googlegroups.com
Caros, estive conversando com o Emerson (Fittipaldi, Urso, barbudo simpático) sobre escrever diretamente no PortA e PortB do Arduino o valor do byte correspondente a configuração de pinos.

Alguém sabe como isso funciona no MEGA ? estou com um 2560. A idéia é escrever os valores diretamente para os pinos de uma memória Flash que usa 8 pinos para endereçar e outros 8 para o dado. Isso seria de grande ajuda, provavelmente vou ter que usar um driver para isso (shift register).

Abraço.

--
======================================
Alejandro Mesias André Nebra Perez
Java/Python/Js/Something else Developer
Twitter: @meszias
Linux User #442506
Campinas - SP - Brasil - South America
======================================

DQ

unread,
Mar 31, 2014, 10:58:35 AM3/31/14
to hacker...@googlegroups.com
Messias,

Não tem segredo. Você só precisa saber qual bit de qual porta corresponde a cada pino.

Um jeito é pegar o esquema do Mega e cruzar com o datasheet do ATmega256.

Outro é você olhar o arquivo pins_arduino.h que está em hardware\arduino\variants\mega. A tabela digital_pin_to_port_PGM informa a porta e digital_pin_to_bit_mask_PGM o bit (ou olhe nos comentários da primeira tabela)

Depois, lembre que cada porta corresponde a três registradores: DDRx que controla a direção (1 = saída), PINx (onde você lê as entradas) e PORTx (onde você escreve as saídas).

O resto é brincar com aritmética binária. Por exemplo, para colocar o pino D39 em 1:

PORTG |= (1 << 2);

Para colocar o mesmo pino em 0:

PORTG &= ~(1 << 2);


DQ

Emerson William dos Santos Moura

unread,
Mar 31, 2014, 1:00:45 PM3/31/14
to hacker...@googlegroups.com
Olá Alejandro, DQ e demais colegas,


Pois é. Estive pesquisando sobre isso por causa do desenvolvimento da biblioteca para o PSG e foi inconclusivo.

** (Explicação para quem quiser entender essa discussão mais no final deste bookmail).

Até onde entendi, os pinos das portas dos microcontroladores Atmega 1280 e 2560 são não sequenciais no pinout do Arduino, para manter funcionalidades nas mesmas posições dos Arduinos "normais" (Diecimila, Duemilanove, Uno etc).

Um exemplo são os pinos digitais 0 a 7 de um Arduino "normal", que são a porta D, bits 0 a 7, enquanto que num Arduino Mega, são bits diversos das portas E, G e H:

E/S digital = pinos no Arduino;
PORT D - bits 0 a 7 = mapeamento físico e de software dos chips Atmega 8/168/328;
PORTs E, G e H - bits variados =  mapeamento físico e de software dos chips Atmega 1280/2560.

E/S digital 0 = PORT D - bit 0 = PORT E - bit 0
E/S digital 1 = PORT D - bit 1 = PORT E - bit 1
E/S digital 2 = PORT D - bit 2 = PORT E - bit 4
E/S digital 3 = PORT D - bit 3 = PORT E - bit 5
E/S digital 4 = PORT D - bit 4 = PORT G - bit 5
E/S digital 5 = PORT D - bit 5 = PORT E - bit 3
E/S digital 6 = PORT D - bit 6 = PORT H - bit 3
E/S digital 7 = PORT D - bit 7 = PORT H - bit 4


Ainda não testei na prática pra saber se a "variável" PORTD aciona os mesmos pinos do Arduino Mega256 através de alguma abstração da biblioteca do ambiente de desenvolvimento do Arduino.


** Explicando para quem não entendeu nada:

No meu caso (biblioteca para acionar o chip de som PSG) e no caso do Alejandro (biblioteca para acionar cartão de memória - é isso, né Alejandro?), temos problemas com tempo (componentes eletrônicos tem especificações de tempo para que um grupo de sinais elétricos sejam acionados).

No caso do chip de som, eu tenho 50uS (micro segundos) para acionar dois terminais para dizer quais informações ele vai receber. Normalmente, em Arduino, fazemos assim:

digitalWrite (pinoX, valorX);
digitalWrite (pinoY, valorY);

O problema, neste caso, é que o tempo de execução entre um comando e outro é maior que os tais 50uS. Então a solução que encontrei no Arduino "normal" é ler o conteúdo de toda a porta (os 8 bits), mudar o que me interessa, e devolver os 8 bits, numa cacetada só, assim:

byte meuByte;

...

meuByte = PORTD; // Essa variável "PORTD" é automaticamente mapeada direto nos 8 bits (0 a 7) de E/S digital.

bitWrite(meuByte, pinoX, valorX); // Ajusta o bit pinoX (0 a 7) com o valorX (LOW ou HIGH).
bitWrite(meuByte, pinoY, valorY); // Ajusta o bit pinoY (0 a 7) com o valorY (LOW ou HIGH).

PORTD = meyByte; // "Manda" os 8 bits (bits 0 a 7) de volta pra porta D numa cacetada só (apenas com os 2 bits mudados).


Como foi tudo de uma vez, o tempo de mudança entre um bit e outro foi ZERO!!!

O problema dos Arduinos Mega128 e Mega256 é que os pinos digitais 0 a 7 estão distribuídos em portas diversas dos microcontroladores Atmega1280 e Atmega2560, como mostrei na tabela lá no começo deste bookmail.


PS: Aqui uma tabela completa de pinos e portas/bits:
<http://bit.ly/1kiRuVg>
http://bit.ly/1kiRuVg


PS2: Se alguém tiver alguma experiência com isso e puder ajudar, gratidão eterna e ainda pago uma breja ou refri no Garoa!





--
.--. .- .-. .- .--. --- ... - .- .-. . ... -.-. .-. . ...- .- .--. .- .-. .- .... .- -.-. -.- . .-. ... .--. .- -.-. . ... .--. .- - --. --- --- --. .-.. . --. .-. --- ..- .--. ... -.. --- - -.-. --- --
Regras da Lista: http://garoa.net.br/wiki/Lista:LeiaAntesDeClicarNoSend
Para mais informações sobre o Garoa Hacker Clube acesse http://garoa.net.br
Maiores opções sobre o Google Groups, visite: http://groups.google.com/group/hackerspacesp
.--. .- .-. .- -- .- .. ... .. -. ..-. --- .-. -- .- . ... .- -.-. . ... ... . --- .-- .. -.- ..
Epoch 0 <=> Fundação: 1298244863 s ~ 2.408064*10^52 tP (tempos de Planck)




--
Emerson W.S.Moura

Alejandro Mesias

unread,
Mar 31, 2014, 1:21:08 PM3/31/14
to hacker...@googlegroups.com
Caraca mermão, que salada. Bom, é trabalho, vou ter que dominar isso por bem ou por mal, rs.

Quando começar a brincar com isso aviso, por enquanto, como estou usando comunicação serial, não faz muita diferença usar isso acredito.

DQ

unread,
Mar 31, 2014, 1:41:29 PM3/31/14
to hacker...@googlegroups.com
Não tem muita salada não.

Em primeiro lugar PORTx não é uma variável e não existe nenhuma abstração envolvida. É hardware!  Felizmente o ATmega mapeia os seus registradores em endereços de memória, o que permite acessá-los diretamente via C.

Infelizmente quem projetou o Arduino Mega não se preocupou em manter a compatibilidade a nível de portas. Uma forma de você ter um fonte único é usar compilação condicional:

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

// instruções para o Arduino Mega

#else

// instruções para o Arduino normal

#endif

Se os bits que você quer mudar estão sempre em uma mesma porta você só precise deixar condicional as definições de portas e bits.

Apareçam na Noite do Arduino que eu tento explicar na prática.


DQ
Reply all
Reply to author
Forward
0 new messages