Tag Archive for Atmel

AtMega128 vs At89s8252 firmware

Pois é, estou desenvolvendo um firmware para uma máquina nova, usando o AtMega128 (Atmel) 16MHz com 256kBytes SRAM externa, 1MB Eeprom externa, etc, mas cada nova rotina deve ser testada, e para isso tem que gravar a Flash do AtMega toda vez… tá bom, a flash dele suporta 10 mil regravações, mas é um saco pensar nisso.   O AtMega128 que estou usando é um TQFP64 soldado na placa de teste, tá bom, é só dessoldar e meter outro, mas, é um saco pensar nisso.

Na época do 8051, usava-se eprom externa, que beleza.  Tinha que apagar, gravar, os cambal, demorava mais, até um dia eu fazer uma engenhoca com SRAM e um código minusculo em eprom.  Na verdade fiz um bootloader, na época que nem se pensava nesse nome.  O código mínimo fazia o 8051 rodar a UART na velocidade mais alta possível aceita pelo PC e esse despejava o novo código a rodar via serial, o 8051 recebia, gravava na SRAM externa e ao final ele mesmo virava um flip-flop e substituia a eprom pela SRAM e o novo código entrava no ar.   Muito rápido e funcional.

Não dá para fazer isso com os AtMega, exceto com um novo chip AVR32 que permite rodar código de memória externa.

A grande vantagem de usar o AtMega128, com 128kBytes de Flash, é que me deixa respirar.   Escrevendo tudo em assembly, é claro, pois *não existe* nenhuma outra linguagem de programação que se possa considerar séria… rsrs… eu sempre me preocupo em reduzir código, reutilizar código, se o mesmo trecho será usado mais de uma vez – passa a ser subrotina, etc e tal.  Essa “neura” consome tempo, e sempre se pensa em fazer um grande código com uma memória flash minuscula.  Não é à toa que tudo o que eu já escrevi na vida, e tem coisa muito complexa, nunca passou de 7kBytes.   Mas agora, com 128kBytes de flash à disposição, eu respiro e a coisa mudou de cor e cheiro, agora eu não mais me preocupo em economizar espaço, nem de Flash, nem de SRAM, e agora eu deito e rolo, me preocupo sim com velocidade de processamento, e tenho medido tudo para garantir que nada mantenha o AtMega ocupado fora do razoável.

Para ter uma idéia, ainda estou na dúvida sobre controlar os displays de sete segmentos, 20 no total, com refresh de 100Hz do AtMega, usando chips 74HC595 e transistores, ou o Max7219, que faz o serviço de refresh sozinho, mas, a rotina do refresh para o HC595 toma só 3.5 microsegundos. Isso é nada, certo?  Simples, eu não faço o bit-bang de mandar bit a bit, eu uso o dispositivo interno do AtMega chamado SPI, é um tipo de serial que pode transmitir a velocidades altíssimas, de no máximo Clock/2, ou seja, 16MHz/2 = 8Mbps, eu soco o byte no registrador da SPI e ela faz o serviço sujo.  Ou seja, 3.5us a cada 10ms, é um overhead de somente 0.035%, com isso garanto que o AtMega estará 99.965% do tempo livre para outras coisas.

Então, com a nova liberdade de flash do AtMega128, hoje eu entendo porque muita gente não gosta de Assembly e prefere C, pois não precisa se preocupar muito com a maneira que o código final ficará, o tamanho dele, a performance, etc.  É mais fácil, mais livre e menos preocupante.

Agora, veja só.   Esse novo firmware que estou escrevendo, parti do scratch, reescrevendo algo que foi escrito para o At89S8252, um 8051 da Atmel, em 1997.  Já está 98% pronto, escrevi em torno de 5 mil linhas de código em assembly e comentários, em menos de 2 semanas, e está ocupando menos de 5kBytes de código, contra os 7k do 8051.

É estranho, que mesmo não me preocupando em economizar espaço, o que escrevo hoje fica menor que o anterior, e então penso, ou o mesmo tipo de código para o 8051 ocupa mais memória que os AVRs, ou depois de 16 anos eu aprendi naturalmente a escrever de forma mais produtiva e inteligente.  Creio que ambos.

O custo de um AtMega128 compensa, pois passa-se a ter 6 e meia portas de 8 bits, (mais de 50 pinos de I/O), 8 ADCs, alguns podendo ser programados para entrada complementar, duas USARTs, PWM de pancada, 128k de Flash, 4k de SRAM interna, 4k de eeprom interna e permite usar SRAM ou I/Os externos como o 8051 o fazia, e acessa-se esses I/Os ou memória externa como uma extensão da interna, maravilha, além de uma carrada de outros dispositivos internos disponíveis.  Ou seja, o AtMega128 vem carregado com tudo que pode, exceto USB e Ethernet.

Eu iniciei nos AVRs brincando com o At90S2313, depois passei para o AtMega8 e naturalmente sai matando o AtMega128.

Tudo bem que uma série de novos chips da concorrência rodam a mais de 50MHz e possuem muita flash, principalmente os novos ARMs da vida.

Mas é muito gostoso trabalhar com um AVR rodando a 16MHz (16 MIPS) e ver a coisa zunir bits à torto e direito.

AVR Assembly – Adição com valor imediato

posted by Wagner Lipnharski @ 1:58pm, Thursday 4 April 2013.

O instruçtion set da familia AVR não possui uma instrução de adição em um registrador com um valor imediato.

Por exemplo, você queira somar o valor fixo “6″ no registrador R18, pela lógica seria a instrução ADDI R14, 0×06, ou, ADI R14, 0×06, mas essa instrução não existe, mas existe a instrução ADD R18, Rnn. Para faze-la, se tem que carregar o valor 0×06 em outro registrador, por exemplo, LDI R20, 0×06, e então efetuar a soma ADD R18, R20.

Mas lembrar que somar +6 é o mesmo que subtrair -6, pois “menos com menos resulta em mais”.

Então, ADDI R18, 0×06 é quase o mesmo que SUBI R18, -0×06, e essa instrução existe.

Outro exemplo, 7+1 é o mesmo que 7-255, o resultado sempre será 8.

Lembrar que -6 também pode ser escrito como 0-6, ou seja, 0xFA.

Então, pode-se escrever SUBI R18, -6 ou SUBI R18, 0xFA.

A diferença entre a suposta ADDI R18, 6 e a SUBI R18, 0xFA, é o carry bit.
Se R18 tivesse um conteúdo de 3, ao somar 6 resultaria em 9, sem carry bit, pois o resultado da soma não ultrapassou 255 e não virou o carry bit. Mas ao subrair 254 (-6 ou 0xFA) de 3, o resultado será 2, 1, 0 -1 -2 -3 ….. até chegar ao 9 esperado, na verdade -9, e o sinal negativo ai é o carry bit que ficou ligado. É só ignorar o carry bit, ou prestar a atenção e tomar a atitude correta com relação ao carry bit.

A forma de fazer o carry bit assumir o valor correto após essa “soma” feita subtração, é comparar o resultado com o valor “6″ que deveria ter sido somado.

Então após a SUBI R18, -6, a instrução Compare Imediate “CPI R18, 6″ fará o serviço correto no carry bit. Veja, como o R18 antes da subtração era “3″, somando 6 ela irá para “9″, e o carry bit deveria estar desligado, mas devido à subtração de -6, ele ficou ligado “indevidamente” para o que se destina. Ao comparar o resultado de R18 com 6, e R18 é 9, o carry bit ficará baixo, pois 9 é maior que 6. Nessa comparação de R18 com 6, o carry bit só ficará ligado quando R18 for entre zero e cinco, ou seja, menor que o valor “6″, e isso só irá ocorrer após a suposta soma com “6″, se o R18 original fosse entre 0xF9 e 0xFF, e a suposta soma com 6 fosse efetivamente gerar o carry bit.

Então, para não usar um segundo registrador para fazer a soma imediata, pode-se sim usar o SUBI R18, -6 ou SUBI R18, 0xF9, mas para acertar o carry bit, em seguida teremos que usar CPI R18, 6.

Mas, necessitando fazer uma soma de valor constante (imediato) à um numero que use mais de 8 bits, ou seja, mais um byte, pode-se fazer toda a operação de soma usando o SUBI, e o SBCI (subtract com valor imediato e com carry) e com isso resolve tudo ao contrário e obtendo o valor certo ao final. Por exemplo 3 bytes, R18, R19 e R20, somando o valor 6 e que propagasse o valor nos 24 bits, considerando que R18 seja o byte de menor ordem, ficaria assim:

SUBI R18, -6
SBCI R19, -1
SBCI R20, -1

Ao subtrair -1 de um número qualquer, ele soma um, mas a instrução SBCI irá também considerar o carry bit na subtração. Se o carry bit estiver desligado, ele irá efetivamente subtrair -1, ou seja, somar 1 no registrador R19 ou R20, no exemplo acima. O carry bit só estará desligado se a instrução anterior efetivamente criaria um carry numa soma, tipo, somar 0x00FF + 0×0004 = 0×103, mas na subi ou sbci tal carry não existiria. Então, o SBCI Rxx, -1 irá só subtrair efetivamente -1 do registrador quando o carry bit estiver desligado, e ele só está desligado quando precisa propagar o carry que não ocorreu.

Ou seja, numa subtração de número negativo, o carry bit funciona ao contrário. Se o carry estiver desligado é porque precisa somar 1 no byte à esquerda, se o carry estiver ligado é porque não precisa somar 1.
Então, é o mesmo que seria (mas não existe):

ADI R18, 6
ADCI R19, 0
ADCI R20, 0

Onde o carry bit se propaga para os bytes de mais alta ordem, e transforma, por exemplo, 00|05|FE + 6 em 00|06|04.

A restrição é que devido à definição de bits nas instruções, a instrução SUBI e SBCI só funcionam nos registradores R16 a R31