CORDIC em Firmware

CORDIC em Firmware
Este post faz parte da série CORDIC - Um processador trigonométrico de ponto fixo. Leia também os outros posts da série:

Caro leitor(a), neste artigo iremos apresentar o início da parte prática descrita no texto anterior, onde apresentamos uma introdução à estrutura básica e funcionamento do processador CORDIC. Vimos que ele pode ser usado em diversos modos, computando diferentes tipos de funções trigonométricas, hiperbólicas e lineares. Observamos também que uma das características que mais chama a atenção é sua simplicidade de construção, sendo necessários apenas operações de deslocamento, adição e uma pequena tabela de somente leitura. Além disso, também foi mostrado que uma vez determinada a resolução desejada, o cálculo de tais funções é executado em tempo constante, ou seja, O(1), sendo indicado para uso em sistemas embarcados de tempo real.

Neste segundo momento vamos aproveitar a simplicidade da estrutura interna do CORDIC e implementar um processador em firmware elementar, que inicialmente será capaz de calcular seno e cosseno de um determinado ângulo. Outras funções poderão ser adicionadas futuramente, mas essas duas primeiras podem ser perfeitas para demonstração, uma vez sendo comum a necessidade de geração de sinais senoidais com microcontroladores de poucos recursos.

O Hardware utilizado, arduino é perfeito para isso

O uso do algoritmo Cordic em software é, de modo geral, pouco recomendado em processadores 32 bits como ARM-Cortex ou RX63, ou microcontroladores de 16 bits mais poderosos como o dsPIC da Microchip, pois essas arquiteturas geralmente são dotadas de recursos de permitem implementações mais poderosas de calculadores de funções lineares e trigonométricas, sendo que já tem em hardware multiplicação, divisão e até mesmo cálculo de raíz quadrada.

A quantidade de memória de programa nesses dispositivos também é bem mais elevada, sendo facilmente superior a 32 KB, aliados a instruções de endereçamento poderosas de 16, 32 e até mesmo 64 bits. Uma tabela de busca em ROM oferece execução em tempo constante O(1), porém com menos latência. Porém a implementação em firmware do algoritmo Cordic é muito bem-vinda em arquiteturas menores, os bons 8 bits que estão na ativa e em muitas aplicações "deep-embedded". É o caso de arquiteturas como PIC, AVR, 8051 e MSP430 - famílias G e F (além de processadores sintetizáveis para FPGA).

O Cordic, para arquiteturas com poucas instruções, exige a mesma coisa para implementações de alto desempenho em hardware. Precisa dos seguintes componentes:

  • 6 registradores de 16 bits (um para cada elemento de rotação);
  • 1 shift registers para executar as multiplicações;
  • 1 somador (ou instrução de soma);
  • 1 tabela com dimensão de Numero de rotações x 16 bits.

Os componentes acima estão sempre disponíveis em "embedded-targets" de arquiteturas dotadas de pouco poder de processamento, que é o caso dos conhecidos arduino Uno e Mega. Ambos possuem um processador de 8 bits AVR dotado de 131 instruções bem poderosas, além do sistema de enderaçamento poderosíssimo com "indexers" (os famosos pares X, Y e Z), geralmente encontrados em arquiteturas maiores, é perfeito para isso.

Abaixo uma cortesia, uma imagem da aquitetura simplificada de um AVR padrão utilizado em Arduinos.

Arquitetura interna do AVR utilizado em Arduinos - CORDIC em Firmware
Figura 1: Arquitetura interna do AVR utilizado em Arduinos

O Firmware de demonstração

O firmware de demonstração buscou ser o mais simples e portável possível, sendo compilável sem qualquer alteração para qualquer outro Arduino. Foi desenvolvido em C++, que no ambiente Arduino é bem mais popular que o tradicional C. Os arquivos cordic.cpp, cordic.h e frac_math_helper.h são responsáveis por implementar a "engine" para cáculo de seno, cosseno e gerenciamento do formato numérico, respectivamente. Falando em formato numérico, essa é outra vantagem do uso do cordic, sua implementação suporta tanto ponto-fixo, como flutuante. Para essa demonstração optamos pelo formato em ponto fixo obedecendo as regras abaixo: 

  • Para os resultados de seno e cosseno, o formato numérico é Q15, ou seja, 15 bits de mantissa com range entre -1 e 1;
  • Para ângulos (passados em radianos, somente!), formato IQ3.12, com 3 bits inteiros e 12 de mantissa, variando entre -7 e 7.

O uso de ponto fixo permite lidar com os problemas de overflow, e ao mesmo tempo oferece macros para conversão entre Q (ponto-fixo) e float (ponto-flutuante). Essas macros são mostradas em frac_math_helper.h abaixo:

A interface e implementação da classe cordic é mostrada abaixo:

Vejam que a rotina de rotação não está disponível por enquanto. A ideia é comentar mais sobre o seu uso na próxima parte desta série, em compensação a resolução pode ser computada em tempo de execução, dependendo dos recursos de memória ou velocidade disponível. Contudo, dado o uso do formato fracionário acima de 24 iterações, a resolução não muda. Para contornar essa limitação, deixo a cargo do leitor reimplementar a classe com um formato mais poderoso como Q31 e IQ7.24, eis a implementaçao de cordic:

A aplicação principal é igualmente simples, apenas computa seno e cosseno de um ângulo de 0º a 90º ou de 0º a -90º (selecionável através de uma constante), e disponibiliza seu resultado via terminal. Na própria IDE do arduino a ferramenta de console pode ser utilizada para verificar o resultado dos cálculos. Dica: Aproveite e teste o resultado dos cálculos com diferentes resoluções. Eis o arquivo principal:

Na seção Links úteis está disponível para o link para o repositório no github, para efetuar um teste rápido. Você pode buscar o projeto diretamente pelo link, ou pela linha de comando, na pasta Arduino (supondo que você tenha o client git instalado em sua máquina), digite:

Abra a IDE Arduino, vá em File->Sketchbook e carregue a pasta demo, conecte seu Arduino à porta USB, e clique no ícone carregar. Ele irá compilar e gravar a imagem na sua placa. Abrindo o terminal serial com velocidade 115200 bps, você deve ver algo assim na tela:

Captura de Tela 2016-06-03 às 8.46.30 PM

Conclusão

Mesmo sendo indicado para ser sintetizado em hardware, o algoritmo cordic, se bem realizado, pode ser uma boa pedida para microcontroladores com poucos recursos e mesmo para ferramentas de protipagem de baixo custo como o Arduino. Pois em todas as suas implementações os componentes básicos sempre estarão disponíveis em processadores de 8 bits. Mas não se engane, apesar de ter escrito que ele nem sempre é a melhor escolha para uso como calculador de funções trigonométricas em processadores maiores, com algumas derivações, o "core" da engine cordic pode ser aproveitado para muitas outras aplicações, inclusive em processamento digital de sinais e modulação em quadratura de sinais (Dica: A engine cordic é uma alternativa super eficiente para modulação em quatratura, pois entrega o resultado de ambas as componentes com um único processamento, e pode ficar ainda melhor se aprovetarmos o set SIMD oferecido nos Cortex-M4/M7).

Ná próxima parte da série, iremos avançar mais, e implementaremos o cordic no lugar onde ele é realmente poderoso, em hardware, será esse meu primeiro post com FPGA aqui pro embarcados. E você leitor, o que achou? Que tal gerar aquela senoide sem precisar recorrer a uma tabela em ROM? Hein? Até a próxima.

Links úteis

Referências

  • ANDRAKA, Ray - A survey of CORDIC algorithms for FPGA based computers;
  • CORDIC FAQ by DSP Guru, disponível aqui 
  • NEVES, Felipe - Rádio definido por software aplicado a ambientes automotivos, 2012

Outros artigos da série

<< CORDIC - Introdução
Este post faz da série CORDIC - Um processador trigonométrico de ponto fixo. Leia também os outros posts da série:
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Software » CORDIC em Firmware
Talvez você goste:
Comentários:

Séries



Outros da Série

Menu