Aqui você encontrará meus projetos, dicas e pesquisas saiba mais

Programando Arduino com Eclipse no Linux Ubuntu

Hoje é dia 15 de novembro de 2011, e resolvi postar essa dica de forma similar à um diário. Domingo à noite (13-11), resolvi revisar um código do identificador e bloqueador de chamadas (projeto esse que ainda vou publicar aqui).

O Problema

Porém, quando abri a IDE padrão do Arduino e pensei em organizar o código, logo me frustrei. Não que ela seja ruim, não mesmo, afinal ela facilita todo o processo de compilação, linkagem e upload do firmware, porém ela tem sérias limitações.

Um exemplo simples é o fato de você não conseguir visualizar mais do que um arquivo que se está editando. Para um simples “hello world” tudo bem, porém um projeto maior exige um código bem organizado e separado em arquivos, e a facilidade de gerenciamento desses arquivos não vem com a IDE do Arduino. Outros detalhes não estão presentes como: auto-complete, navegação entre chamadas de função (Ctrl + click do mouse sob a função), identação personalizada, entre outros fatores que programadores que já usaram NetBeans ou Eclipse sentem falta.

A solução

Sempre fui à favor de que a melhor tecnologia é aquela que melhor resolve seu problema. Isso inclui, gosto do programador, facilidade em aprender e o fato de ser multiplataforma (afinal quero poder trocar scripts com meus amigos!). Como sempre usei Netbeans, o primeiro teste que fiz foi tentar editar os scripts do Arduino com essa IDE. Fiz testes seguindo este tutorial, consegui fazer rodar certinho, porém me deparei com problemas como:

  • Editar o MakeFile manualmente adicionando inclusões de cabeçalhos necessários;
  • A falta de um comando específico para compilar tudo e fazer o upload do firmware para o chip;
  • A sensação de que estava programando em um ambiente “adaptado”.

Me sentindo mal por não poder dizer com tesão: “Estou programando profissionalmente Arduino!” (olha que afirmação irônica hehe), resolvi testar uma das soluções oficiais encontrada no site do Arduino: O Eclipse.

Preciso admitir que sempre achei interessante a ideia qual o Eclipse funciona, muitos plugins, permitindo desenvolver em diversos senários e tecnologias. O único problema é que iniciar o tutorial do Eclipse para Arduino foi um verdadeiro “caindo de paraquedas”, afinal nunca programei microcontroladores “na unha” e minha experiência com programação nestes dispositivos ainda é muito pequena. Por isso demorei bastante até finalmente conseguir rodar o maravilhoso Ctrl + B!

Basicamente o que o tutorial ensina fazer é:

  • Instalar o AVR Eclipse Plugin;
  • Instalar os pacotes pendentes para o ambiente de desenvolvimento;
  • Criar a biblioteca core do Arduino pré-compilando pacotes (foi difícil entender o que isso singificava);
  • Finalmente, a criação do primeiro projeto Arduino no Eclipse;
  • Outros itens que não serão abordados aqui.

Instalando pré-requisitos

Primeiramente instale os pacotes necessários para trabalhar com a arquitetura AVR, simplesmente instalando:

# apt-get install avrdude binutils-avr gcc-avr avr-libc gdb-avr

O avrdude é o programa que será usado para fazer a gravação do arquivo .HEX no CHIP. Outros pacotes são para criar e manipular arquivos binários criados para a arquitetura AVR.

Instalando O Eclipse

Instalar o eclipse, acredito eu, você não terá dúvidas de como faz, mas vale ressaltar que usei a versão Eclipse IDE for C/C++ Developers, e claro o JDK corretamente configurado no PATH do sistema.

Instalando o AVR Eclipse Plugin

Bom, após instalar o Eclipse, o primeiro passo é instalar o plugin que irá permitir o desenvolvimento para a arquitetura AVR. Para isso basta seguir os passos à seguir:

Na aba Help, vá até "Install new Software" e clique em "Add". Preencha o nome com "AVR Eclipse Plugin" e a URL com "http://avr-eclipse.sourceforge.net/updatesite/"

Depois, selecione os dois pacotes encontrados e avance a instalação

Após confirmar os plugins a serem instalados, prossiga a instalação normalmente e reinicie a IDE

Criando a biblioteca Core do Arduino

Nesta etapa, iremos criar a biblioteca Core do Arduino, que servirá de base para todos os projetos que iremos desenvolver.

Parte 1 – Criando um projeto Eclipse

Esse não é um projeto comum qual iremos brincar, e sim uma base para a criação de todos os outros projetos Arduino. Os passos são simples:

Clique em “File” -> “New” -> “C++ Project” no Eclipse. E selecione um projeto vazio dentro da sessão AVR Cross Target Static Library.
Dentro dos tipos de projetos, deixe apenas a opção “Debug” marcada.
Por fim, selecione o tipo de processador utilizado (no meu caso Atmega328P) e sua frequência (16Mhz = 16000000Hz)

Uma vez criado o projeto, precisamos criar a pasta que conterá os arquivos fonte. Para isso tendo selecionado o projeto arduino_core, clique no menu “File” -> “New” -> “Source Folder” e crie uma pasta fonte com o nome “src”.

1 - Clique em "File" -> "New" -> "C++ Project" no Eclipse. E selecione um projeto vazio dentro da sessão AVR Cross Target Static Library'

2 - Dentro dos tipos de projetos, deixe apenas a opção "Debug" marcada.

3 - Por fim, selecione o tipo de processador utilizado (no meu caso Atmega328P) e sua frequência (16Mhz = 16000000Hz)

4 - Criar pasta de fontes: "File" -> "New" -> "Source Folder" e crie uma pasta fonte com o nome "src"

5 - Estrutura básica de um projeto de bibliotecas estáticas do Arduino

Parte 2 – Configurando destinos de Construção e propriedades do hardware

Nesta etapa são feitos os tipos de configurações, além da padrão Debug, iremos adicionar todas as configurações quanto processadores que tivermos. No meu caso criei mais três configurações: 8PU_16MHz, 328P_16MHz e 1280_16MHz que são os CHIPs qual possuo. Esses nomes claro, você pode alterar à vontade, porém não use espaços nem caracteres especiais.
Em cada configuração criada, iremos copiar as definições da configuração Debug e por fim, iremos excluí-la. Para tanto, siga os seguintes passos:

1 - Estando com seu projeto arduino_core selecionado, vá no menu "Propriedades" e então expanda a opção C/C++ Build

2 - Clique então em "Manage Configurations" e depois no botão "New...", defina o nome como: 328P_16MHz e a descrição que desejar. Por fim clique em "OK"

3 - Repita o passo anterior para todos os seus processadores (alterando claro, o nome). Feito isso, você já pode excluir a configuração Debug

4 - Clique então no menu "AVR" e marque a opção "Individual settings for build configurations" e clique em "Apply"

5 - Agora vá no submenu "Target Hardware" dentro de "AVR" e para cada configuração criada, certifique-se de selecionar o processador certo (dentro de MCU Type), e claro sua frequência (para mim todos usam oscilador de 16000000Hz)

Parte 3 – Ajustando configurações do compilador C

Nesta sessão iremos fazer ajustes de construção do projeto. Entre estes estão: Alterar todas as configurações ao mesmo tempo, desativar degugger, ativar compactação do arquivo .HEX gerado pelo compilador (arquivo que será gravado no chip), alterar opções de idioma e por fim configurar a pasta onde estão contidos os arquivos fonte.

1 - Estando nas propriedades do projeto acesse a sessão Settings dentro do menu C/C++ Build. Importante: Selecione a opção de configuração "All Configurations" para então prosseguir. Do contrário você terá muito mais trabalho (refazendo as configurações para cada perfil criado)

2 - Dentro de "Settings", acesse o submenu "Debugging" dentro do menu "AVR Compiler" e em "Generate Debugging info" selecione a opção "No debugging info" e aplique as opções clicando em "Apply"

3 - O próximo passo é configurar a redução do tamanho do arquivo HEX. Para isso, Vá no submenu "Optimization" e defina o nível de otimização para "Size Otmizations (-Os)" e em Outros, insira estes parâmetros: "-ffunction-sections -fdata-sections". Por fim, desmarque as 2 opções "Pack structs" e "Short enums". Lembre-se de aplicar as modificações.

4 - Em "Language Standard" ainda dentro de "AVR Compiler", desmarque as duas opções: "char is unsigned" e "bitfields are unsigned"

5 - Agora em "Directories" dentro ainda da sessão "AVR Compiler", clique no ícone para Adicionar (sinal de +), clique em "Workspace...", expanda a pasta arduino_core e selecione a subpasta (criada anteriormente) src. Pressione então "OK"

6 - Certifique-se que a inclusão de caminho ficou igual a: "${workspace_loc:/${ProjName}/src}"

Parte 4 – Ajustando configurações do compilador C++

As configurações do compilador C++ são praticamente iguais as do C. Então prossiga com os mesmos passos feitos na sessão anterior agora para o “AVR C++ Compiler”.

Não se esqueça de selecionar novamente "All configurations" dentro de "Configurations" (quando sai do menu "Properties" e volta, ele retoma esta opção para a Default.

Nas opções de Língua, você deve deixar ativada a opção: "Do not use Exceptions" ativada

Parte 5 – Instalando arquivos fontes

Nota importante: Vi hoje (01-12-11) que saiu a versão 1.0 do Arduino, e estou modificando este tutorial para esta versão. Portanto percebi que após copiar todos os arquivos fontes, um deles não está na mesma pasta, que é o arquivo pins_arduino.h usado pelo Arduino.h (substituto do WProgram.h). Logo o que fiz foi copiar também o arquivo “arduino-1.0/hardware/variants/standard/pins_arduino.h” para a pasta src do Eclipse.

Nota ainda mais importante: Ontem à noite (01-12-11) estava quase terminado o tutorial, porém houve um problema sério: ao gravar o firmware no CHIP ele simplesmente não funcionava. Refiz os testes e fui dormir frustrado. Hoje, depois de diversas pesquisas descobri que:

  • Se for usar a versão 0022 do Arduino e o avr-libc versão 1.7.1 (qual estou usando), cuidado com o bug do wiring.h. Na linha 79 você precisará comentar a redefinição da função round(). Ok, mas isso somente se você usar os fontes da versão 0022. Descobri isso, pois tentei aplicar o tutorial nesta versão antiga e tive estes problemas.
  • Bom, a versão 0022 é passado, agora estamos na versão 1.0 do Arduino então nada mais justo que usá-la aqui. Sem mais delongas, o que ocorre é que a nota anterior está incompleta (mas então por que não vai lá e muda-a? Bom: assim é mais emocionante, acredite!). A pasta “arduino-1.0/hardware/variants”, como o nome já indica, possui variações de versões e no momento o único arquivo que está variando é o nosso amigo pins_arduino.h. Em resumo: Acesse esta pasta e você encontrará as seguintes pastas: “eightanaloginputs”, “leonardo”, “mega”, “micro” e “standard”.Aqui temos um problema sério quando estamos falando em configurar nosso projeto com mais que uma
    configuração (usando Atmega328 e Mega1280 por exemplo). Como cada um usa um arquivo pins_arduino.h diferente, fica impossível usar essa opção, afinal não irá funcionar (eu garanto isso, fiz testes!). Temos então duas opções: 

    • Podemos criar um projeto (arduino_core) novo para cada processador diferente
    • Ou editamos o arquivo pins_arduino.h adicionando macros que irão verificar qual a versão do Arduino que está sendo compilada e então definir o código adequado

    Se você está seguindo este tutorial, possivelmente tem mais que um modelo de CHIP, então faça o download aqui do arquivo pins_arduino.h já editado e copie-o na sua pasta src junto com todos os fontes do Arduino. Porém veja que eu apenas inseri macros para os modelos Atmega8, Atmega328P, atmega1280 e atmega2560, que são os que eu uso no momento. Você pode facilmente editar esse arquivo copiando o conteúdo dos que você irá usar.

    Atenção: Essa solução não é oficial. Enquanto o site oficial não lançar uma atualização do tutorial (qual foi feito para versões anteriores à 1.0 do Arduino) continuarei usando-a. A pesar de ser uma “quase-ganbiarra”, ela funciona muito bem e evitará muito trabalho! Porém lembre-se: ela só é necessária caso você trabalhe com mais de um CHIP e não queira criar um projeto para cada um deles.

O primeiro passo é copiar, os arquivos fontes do núcleo do arduino (presente em arduino-1.0/arduino-1.0/hardware/arduino/cores/arduino) para a pasta src criada anteriormente

Vamos ativar a construção de todas as configurações simultaneamente. Vá no menu "Window" -> "Preferences", navegue dentro de "C/C++" e acesse o submenu "Build". Marque a opção "Build all configurations in each project". Aplique as modificações e pressione "OK"

Finalmente, rodando então "Project" -> "Build All" a construção do arquivo Core (libarduino_core.a) para cada configuração será um sucesso!

O primeiro projeto Arduino

Exatamente, o que fizemos até agora foi criar os arquivos de biblioteca (libarduino_core.a) para então podermos trabalhar com nossos projetos. Concordo que a opção de copiá-los de uma compilação já feita (uma das sugestões do tutorial oficial) seria uma tarefa mais fácil, porém assim temos mais controle e não precisamos ficar indo de uma IDE para outra.

1 - Crie um novo "C++ Project" e agora selecione "Empty Project" dentro de "AVR Cross Target Application". Veja que é diferente do projeto anterior

2 - Desmarque a configuração "Release"

3 - Selecione o processador e afrequência correta

4 - Nas propriedades do projeto criado, vá em "Settings" dentro de "C/C++ Build". Marque todas as opções menos "Generate HEX file fro EEPROM". A opção AVRDude irá gravar no chip o programa para cada compilação feita

5 - Da mesma forma que fizemos antes, apenas desative informações de Debugging dentro de "AVR Assembler"

6 - Em "Directories" do menu "AVR Compiler" adicione a pasta src do arduino_core. Veja que aqui fazemos uma das 'conexões' entre o projeto anterior (biblioteca estática) e esse

7 - Desative informações de Debugging dentro de "AVR Compiler"

8 - Como feito no outro projeto, ative opções de otimização usando o flag: "-ffunction-sections -fdata-sections" e desativando "Pack structs" e "Short enums"

9 - Desative as opções "char is unsigned" e "bitfields are unsigned" dentro de "Language Standard" no menu "AVR Compiler"

10 - Como feito anteriormente, em "Directories" porém agora dentro do menu "AVR C++ Compiler" insira o caminho para a pasta src do projeto arduino_core feito anteriormente

11 - Desative informações de debugging dentro de "AVR C++ Compiler"

12 - Repita as configurações de otimização feitas até agora

13 - Em "Language Standard" dentro de "AVR C++ Compiler" deixe marcado apenas a opção "Do not use Exceptions"

14 - Com o intuito de dinimunir o tamanho do fonte C++, dentro de "AVR C++ Linker" defina as seguintes opções em "Command line pattern": "${COMMAND} --cref -s -Os ${OUTPUT_FLAG} ${OUTPUT_PREFIX} ${OUTPUT} ${INPUTS} -lm ${FLAGS}"

15 - Este passo é muito importante. Em "Libraries Path", insira o caminho para a pasta do processador criada no projeto arduino_core. E em "Libraries" insira o nome arduino_core (correspondente ao libarduino_core.a) e simplesmente m (este segundo o tutorial a IDE do Arduino também usa)

16 - Em "General" ainda dentro de "AVR C++ Compiler" em "Other Arguments" insira: "-Wl,--gc-sections"

17 - Opcionalmente, se você deseja ver o arquivo de símbolos (contém funções, variáveis etc), ACRESCENTE ao "Command Line Pattern" o seguinte: "; avr-nm -C -n ${OUTPUT} >${BuildArtifactFileBaseName}.symbol"

Configuração final: O gravador

O último passo para o primero teste, é configurarmos o gravador correto e fazermos um código fonte inicial mínimo.

Para configurar o gravador vá em "AVRDude" dentro do menu "AVR" nas propriedades do projeto. Clique então em "New..." dentro de "Programmer configuration"

Dê um nome ao gravador e selecione o "Arduino" dentro de "Programmer Hardware". Em "Override default port" coloque o endereço da porta usb qual o Arduino é reconhecido. Por fim defina a velocidade padrão para 57600

Faça seu primeiro upload com um código fonte simples (obtido do core do Arduino-1.0) clicando com o botão direto sobre o projeto e depois em "Build Project". E a mágica acontecerá!

Adicionando bibliotecas externas

Em praticamente todos os projetos iremos fazer uso de bibliotecas de terceiros, seja um display LCD ou um sensor de distância, você normalmente precisará usar um recurso extra em seu projeto.
Para podermos usar essas bibliotecas, primeiro precisamos incluí-las na pasta “src” do projeto “arduino_core” e então recompilar o projeto (que irá refazer os arquivos libarduino_core.a de cada configuração feita).
O problema é que não basta copiar a pasta inteira (por exemplo a Ethernet) para a pasta “src”, precisamos adicionar alguns includes na hora de compilar (ou seja executar o avr-g++).

Um exemplo desta necessidade mostrarei aqui. Ao copiar a pasta Ethernet e SPI (ambas do pacote padrão Arduino-1.0) e compilar, o primeiro erro que gera-se é este:
In file included from ../src/Ethernet/utility/socket.cpp:1:0:
../src/Ethernet/utility/w5100.h:14:17: fatal error: SPI.h: No such file or directory
compilation terminated.
make: *** [src/Ethernet/utility/socket.o] Error 1

Isso acontece, pois o arquivo w5100.h inclui logo no início (linha 14) o arquivo SPI.h, porém este não está no mesmo nível que aquele e também não está nos includes padrões do sistema operacional. Logo, o que precisamos fazer é adicionar os respectivos includes para poder compilar com sucesso a biblioteca Ethernet juntamente com a SPI.

Em resumo da história, o comando executado pelo Eclipse foi:
avr-g++ -I”/home/paulo/workspace/arduino_core/src” -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF”src/Ethernet/utility/socket.d” -MT”src/Ethernet/utility/socket.d” -c -o “src/Ethernet/utility/socket.o” “../src/Ethernet/utility/socket.cpp”

Porém deveria ter sido:
avr-g++ -I”/home/paulo/workspace/arduino_core/src” -I”/home/paulo/workspace/arduino_core/src/Ethernet” -I”/home/paulo/workspace/arduino_core/src/Ethernet/utility” -I”/home/paulo/workspace/arduino_core/src/SPI” -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF”src/Ethernet/utility/socket.d” -MT”src/Ethernet/utility/socket.d” -c -o “src/Ethernet/utility/socket.o” “../src/Ethernet/utility/socket.cpp”

Perceba a sutil diferença. Estamos compilando para um processador Atmega328P (-mmcu=atmega328p) com clock de 16MHz (-DF_CPU=16000000UL) com os includes corretos (…/src, …/src/Ethernet, …/src/Ethernet/utility e …/src/SPI). Note que essas saídas são exibidas pelo Eclipse, ele também gera um arquivo de log: /home/paulo/workspace/.metadata/.plugins/org.eclipse.cdt.ui/global-build.log (em seu home claro) qual pode ser muito útil em casos de erros de compilação. Uma regra regral que aprendi com isso é que você precisa aprender a compilar manualmente (os includes por exemplo, precisamos saber como eles são passados para avr-g++) isso será muito útil também para qualquer outro tipo de programa em C, embarcado ou não!

Atenção: Sempre que for voltar a fazer as configurações em seu projeto, certifique-se de que você está editando a configuração certa. Para adicionar includes extras, sempre selecione em “Configuration” dentro do menu “Properties” do projeto, a opção “[All configurations]“.

Inicialmente, ao usar uma biblioteca sem incluir, o Eclipse irá avisar que faltam os cabeçalhos (veja linha 2 e 3 do arquivo)

Se você apenas copiar as pastas de biblioteca (Ethernet e SPI neste exemplo) para o projeto arduino_core (na pasta src obviamente), e mandar compilar, receberá esta mensagem de erro: "SPI.h: No such file or directory"

Para resolver, apenas vá em "Directories" dentro do menu "AVR C++ Compiler" e ali insira os include Paths nescessários.

Finalmente, tudo pronto e funcionando!

É com muito orgulho que digo pra você agora: “vai programar rapaz!”

Depois de tantas configurações, o ambiente finalmente está pronto!

Referências

http://code.google.com/p/arduino/wiki/Arduino1
http://www.arduino.cc/playground/Code/Eclipse
http://code.google.com/p/arduino/issues/detail?id=604
http://avr-eclipse.sourceforge.net/wiki/index.php/Plugin_Download

Minha reflexão

Entender e fazer este tutorial foi mais trabalhoso do que eu imaginava, porém o resultado final foi muito gratificante. É fantástica a emoção de usar um ambiente de desenvolvimento “destravado”. Meu pensamento momentâneo que tenho de compartilhar é: A teimosia bem usada é uma excelente ferramenta. Seja teimoso com o computador, ele precisa que o façam. Porém cuidado para não se apegar demais nessa ideia.

5 Comentários para “Programando Arduino com Eclipse no Linux Ubuntu”

  1. Parabéns você gastou muita energia, mas chegou ao seu resultado e compartilhou com a humanidade.

  2. Olá amigo Felipe, obrigado.

    Foi muito interessante fazer este tutorial, e agora ficou muito mais prático programar projetos de médio e grande porte com Arduino.

    Abraço!

  3. Valeu pela postagem!

    Eu também faço como vc, não utilizo a IDE do Arduino para programar. Uso o Windows e as seguintes ferramentas: MinGW, Notepad++, avr tools (dentro das pastas do Arduino IDE) e o Proteus (para debugger). Utilizado arquivos “Makefile” não fica dificil a configuração. Desse seu modo vc reúne tudo em um só aplicativo.

    Parabens!

  4. Oi Bruno, que bom que gostou!
    Realmente, reuní tudo em um único aplicativo, o que facilitou o processo geral. Em projetos grandes isso é uma mão na roda. Uso ainda a IDE do Arduino, porém apenas em pequenos testes, afinal é bem mais prática para esse fim.

  5. Oi Paulo, eu de novo. Tenho uma pergunta. Tem como eu depois de escrever um código no Arduino eu ver ele funcionando em imagens igual a do Fritzing?

Deixe um comentário