Planet ccppbrasil.org

September 01, 2010

Sergio Prado

Resenha: Embedded Software The Works

Terminei recentemente a leitura do Livro “Embedded Software The Works”, escrito por Colin Walls, experiente engenheiro e um dos pioneiros da indústria de sistemas embarcados, que trabalha atualmente na Mentor Graphics. O livro é uma coletânea de vários artigos, separados por temas de interesse em 9 capítulos. 

A linguagem utilizada é simples, e apesar de manter certa ordem de apresentação do conteúdo, você não precisa ler na ordem apresentada. Alguns artigos, que foram escritos na década de 90, estão um pouco defasados, mas no geral é um livro que vale a pena pelo menos dar uma olhada em alguns capítulos, que são bem interessantes.

O capítulo 1 apresenta uma introdução à sistemas embarcados e sua evolução durante os últimos 30 anos, falando sobre memória, arquitetura de CPUs e seu processo de seleção, além de dois artigos bem interessantes sobre a interface USB. O capítulo 2 é sobre design de sistemas embarcados, abrangendo tópicos como UML e Eclipse. 

Os capítulos 3, 4 e 5 são inteiramente voltados ao desenvolvimento de software embarcado em C e C++, com algumas dicas valiosas principalmente para quem está começando na área. Os capítulos 6 e 7 também são bem interessantes, discutindo tópicos relacionados à sistemas de tempo real. Os dois últimos capítulos falam sobre protocolos de rede e FPGAs.

O site do livro é este aqui, e quem se interessar pode dar uma folheada no Google Books. Vale a pena também acompanhar o The Colin Walls Blog.

Um abraço!

Sergio Prado

Posts relacionados:

  1. Misra-C — Padrão para software em C
  2. Como se tornar um desenvolvedor de software embarcado

by sergioprado at September 01, 2010 11:00 AM

August 30, 2010

Pedro Lamarão

Por que goto é considerado prejudicial?

Recentemente, o Fabiano Vasconcelos abriu uma discussão no Grupo de Usuários de C e C++:
De cara eu vi algo aqui um pouco estranho, se que o amigo Márcio me permite comentar: que muitos programadores, inclusive eu (se que posso ser rotulado como programador) foram instruídos com o princípio de NUNCA usar o goto, por ser considerado um mau estilo de programação.
Durante a discussão, o Eduardo Vieira puxou um artigo da KernelTrap sobre uma discussão similar ocorrida no grupo de desenvolvimento do Linux, onde Robert Wilken disse o seguinte:
In general, if you can structure your code properly, you should never need a goto, and if you don't need a goto you shouldn't use it. It's just "common sense" as I've always been taught. Unless you're intentionally trying to write code that's harder for others to read.
É preciso colocar a máxima "goto considered harmful" na perspectiva histórica adequada.

Acredito que praticamente todo programador treinado nos últimos vinte anos aprendeu a programar com if e while. Essas são as estruturas básicas de programas e aparecem rapidamente nos manuais e nos cursos de programação. Toda linguagem de programação moderna tem if e while, e variantes como switch, for etc.

Essas coisas são chamadas estruturas de controle porque fazem exatamente isso: controlam a execução do programa, às vezes indo para uma sequência de sentenças, às vezes indo para outra, de acordo com testes explícitos. Arranjar um programa com sequências de sentenças, if e while é fazer programação estruturada.

Agora, a não ser que algum curso maravilhoso e desconhecido por mim tenha história da programação no seu currículo, este programador provavelmente não percebe que if e while nem sempre existiram e que a programação estruturada foi inventada mais ou menos na década de 70.

Durante a discussão no grupo de desenvolvimento do Linux, Scott Robert Ladd disse o seguinte:
Your attitude against "goto" is perhaps based upon an excellent but dated article, "Goto Considered Harmful", written by Edsger W. Dijkstra, and published by the ACM in 1968. (A recent reprint can be found at http://www.acm.org/classics/oct95/.) As you can tell from the date, this article predates modern programming languages and idioms; it comes from a time when Fortran ruled, and before Fortran 77 provided significant tools for avoiding spaghetti code.
e mais o seguinte:
Used over short distances with well-documented labels, a "goto" can be more effective, faster, and cleaner than a series of complex flags or other constructs. The "goto" may also be safer and more intuitive than the alternative. A "break" is a goto; a "continue" is a "goto" -- these are statements that move the point of execution explicitly.
Dijkstra, e outros, iniciaram a pequena revolta estruturada e assim ocorreu que diversas linguagens de programação introduziram novidades como if e while. Mas como é possível programar sem if e while?

Considere este fragmento:

char * i = input;
while (*i != '\0')
 if (*i == SPECIAL) goto exit;
 else ++i;
:exit
return i;

Este fragmento _não_ é o objeto da objeção ao uso de goto. Este fragmento exibe honrada programação estruturada. goto está ali como bem poderia estar break. Tanto faz.

Agora, observe este fragmento:

char * i = input;
:loop
if (*i == '\0') goto exit;
if (*i == SPECIAL) goto exit;
++i;
goto loop;
:exit
return i;

Isto é o que você deve evitar.

O objetivo do combate ao goto era combater a programação não-estruturada, e esse combate foi vencido com a introdução das linguagens estruturadas. Tais linguagens levam o programador naturalmente ao caminho certo e proíbem os maiores absurdos.

Existem linguagens em que o último fragmento acima era _a única alternativa_. (Ou coisa pior.)

Em retrospectiva, sabemos que a programação não-estruturada dominante na época causava um modo de pensar não-estruturado sobre os programas, de modo que o "spagetthi code" clássico era um único fluxo de instruções com gotos arbitrários para cima e para baixo, algo muito pior que o último fragmento acima, o tipo de código que eu não saberia construir artificialmente.

Se você conhece e pratica a programação de acordo com os bons princípios da programação estruturada, não precisa temer o goto. Existem diversas situações excepcionais às quais as estruturas de controle do C não se adequam perfeitamente; aquela que me ocorre com mais frequência são switches dentro de for quando é preciso terminar o for dentro de um case.

for (char * i = input; *i != '\0'; ++i)
 switch (state)
 {
 case FOO:
  /* many things */
  break;
 case BAR:
  if (*i == SPECIAL) goto exit;
  /* many things */
  break;
 }
exit:

Sempre existe uma maneira de remover o goto; nem sempre essa maneira é desejável. O goto acima, cujo label está exatamente na saída do laço, me parece uma parte bastante adequada da estrutura de controle. Java, que não possui goto, permite dizer "break exit", com exatamente o mesmo significado.

Durante a discussão no grupo de desenvolvimento do Linux, Robert Love disse o seguinte sobre a substituição do goto por outras estruturas:
As a final argument, it does not let us cleanly do the usual stack-esque wind and unwind, i.e.
do A
if (error) goto out_a;
do B
if (error) goto out_b;
do C
if (error) goto out_c;
goto out;
out_c:
undo C
out_b:
undo B:
out_a:
undo A
out:
return ret;
Now stop this.

by P. (noreply@blogger.com) at August 30, 2010 03:37 PM

Sergio Prado

Mini2440 — Linux com U-Boot e Emdebian

No último artigo vimos com mais detalhes a arquitetura do kit FriendlyARM mini2440 e o bootloader que vem instalado de fábrica. Quem ainda não leu este post, pode acessá-lo aqui.

Vamos agora colocar a mão na massa. Nosso objetivo aqui é carregar na flash NAND o bootloader U-Boot, bastante usado em sistemas embarcados, e depois fazê-lo carregar uma imagem do Emdebian, uma versão do Debian mais leve.

O único pré-requisito é um kit FriendlyARM mini2440 conectado à uma máquina Linux pela serial (para acessar a console), pela USB (para transferir a imagem do U-boot) e por um cabo de rede (para carregar as imagens do kernel e do rootfs do Emdebian).

Usei o binário do U-boot deste link aqui. O kernel eu baixei daqui, mas precisei customizá-lo para habilitar o suporte à sistema de arquivos JFFS2 e corrigir o mapeamento das partições da MTD no driver da Flash. O rootfs eu peguei aqui, mas também precisei "dar um tapa", e corrigir um problema que impedia de subir o terminal pela console RS232.

Para facilitar o trabalho daqueles que irão executar este passo-a-passo, criei um "pacote especial" com todas as ferramentas e imagens necessárias para dar vida ao Emdebian no mini2440. Este pacote pode ser baixado aqui. Descompacte-o para sua máquina e mãos à obra!

Bootloader U-Boot

O bootloader é uma aplicação que é carregada e executada assim que o hardware é ligado. No universo desktop, estamos familiarizados com o LILO ou o GRUB para carregar sistemas Unix-like, mas no universo embedded as coisas são um pouco mais complicadas. Um bootloader para sistemas embarcados possui 3 principais responsabilidades:

  1. Inicializar o hardware.
  2. Possibilitar a carga e gravação da aplicação na flash via alguma interface de I/O, como porta serial, USB ou interface de rede.
  3. Carregar e executar aplicações da RAM.

Um bootloader bem conhecido no universo embedded é o Das U-Boot, também conhecido apenas como U-Boot, um bootloader multi-plataforma e open-source, com suporte à diversas arquiteturas como PowerPC, ARM, MIPS, Coldfire e x86. A página do projeto pode ser acessada aqui.

O U-Boot será o bootloader que utilizaremos para carregar o Emdebian pela NAND. O processo para carregar e gravar o U-Boot na flash é simples.

Primeiro iremos carregar a imagem do U-Boot na RAM. Para isso precisaremos da imagem do U-Boot ("u-boot-256M.bin" ou "u-boot-128M.bin", dependendo do seu kit), e da ferramenta "usbpush". Todos os arquivos encontram-se no link que passei no início deste post. Não esqueça também que a serial e a USB devem estar conectadas.

Inicie o kit pela NOR, no menu do supervivi selecione a opção "q" e prepare-o para receber a imagem do U-Boot e salvar em RAM:

[q] Goto shell of vivi
Enter your selection: q
Supervivi> load ram 0x31000000 242360 u

Obs: O parâmetro "242360" deve ser o tamanho em bytes da imagem do U-Boot ("u-boot-256M.bin" para a flash de 256M no meu caso).

Então, em um shell do Linux, digite o comando abaixo:

$ sudo ./usbpush u-boot-256M.bin

A console irá exibir uma mensagem indicando que a transferência foi realizada com sucesso.

Agora iremos executar o U-Boot da RAM mesmo, assim podemos formatar a NAND e depois copiar o U-Boot para lá.

Digite então na console do mini2440:

Supervivi> go 0x31000000

Após algumas mensagens, irá aparecer o shell do U-Boot. Agora vamos formatar a flash. A execução dos comandos abaixo podem demorar um pouco, portanto tenha paciência :)

MINI2440 # nand scrub
....
MINI2440 # nand createbbt
....

Depois é só escrever o U-Boot na flash Nand.

MINI2440 # nand write.e 0x31000000 0 242360

Obs: Não se esqueça de que novamente o parâmetro "242360" deve ser o tamanho em bytes da imagem do U-Boot.

Muito bem. Você acabou de instalar o U-Boot na sua flash NAND. Desligue a placa, mude a chave para bootar pela NAND para a console cair no shell do U-Boot.

Este bootloader tem bastante recursos. O comando "help" vai exibir uma lista. Podemos por exemplo listar informações da placa ou das partições da flash, conforme abaixo:

MINI2440 # bdinfo
arch_number = 0x000007CF
env_t       = 0x00000000
boot_params = 0x30000100
DRAM bank   = 0x00000000
-> start    = 0x30000000
-> size     = 0x04000000
ethaddr     = 08:08:11:18:12:27
ip_addr     = 10.0.0.111
baudrate    = 115200 bps
 
MINI2440 # mtdparts 
device nand0 <mini2440-nand>, # parts = 4
 #: name                size            offset          mask_flags
 0: u-boot              0x00040000      0x00000000      0
 1: env                 0x00020000      0x00040000      0
 2: kernel              0x00500000      0x00060000      0
 3: root                0x0faa0000      0x00560000      0
active partition: nand0,0 - (u-boot) 0x00040000 @ 0x00000000
</mini2440-nand>

Podemos carregar uma aplicação via serial com os comandos "loadb", "loads" e "loady", via NFS com o comando "nfs", via TFTP com o comando "tftpboot" ou via USB com o comando "usbboot". Podemos também testar a RAM com os comandos "mtest" e "mw".

Carregando o Emdebian

O Emdebian é uma versão do Debian para sistemas embarcados. Mantém as principais características do Debian, como sistema de gerenciamento de pacotes, sistema de licenças e portabilidade entre diversas plataformas. O sistema de build é customizado para trabalhar com pacotes pequenos e gerar distribuições bem mais leves. A página do projeto pode ser acessada aqui.

A carga do kernel ("uImage") e do rootfs ("emdebian-jffs2.img") é feita através de uma conexão de rede. Ligue seu PC com o mini2440 através de um cabo de rede, configure o endereço IP do seu PC com 10.0.0.1, e o do kit com 10.0.0.2. Configure o mini2440 através dos comandos abaixo na console do U-Boot:

MINI2440 # dynenv set 40000
MINI2440 # setenv ipaddr 10.0.0.2
MINI2440 # setenv serverip 10.0.0.1
MINI2440 # saveenv

Use o comando "ping 10.0.0.1" na console do U-Boot para verificar se a conexão com o PC está funcionando corretamente.

Vamos agora gravar o kernel. O processo consiste em carregar a imagem do kernel para a RAM, e então de lá gravar na flash:

MINI2440 # tftp 0x31000000 uImage
MINI2440 # nand erase kernel
MINI2440 # nand write.e 0x31000000 kernel 0x205f58

Para o rootfs, o processo é idêntico:

MINI2440 # tftp 0x31000000 emdebian-jffs2.img
MINI2440 # nand erase root 
MINI2440 # nand write.e 0x31000000 root 0x23e0000

Agora só falta setar as variáveis de ambiente do U-Boot para iniciar o kernel do Linux corretamente:

MINI2440 # setenv bootcmd nboot.e kernel ; bootm
MINI2440 # setenv bootargs root=/dev/mtdblock3 rootfstype=jffs2 console=ttySAC0,115200
MINI2440 # saveenv
MINI2440 # boot

Pronto! O Emdebian já está rodando no nosso kit mini2440:


Quando comecei a escrever este post, minha intenção original era carregar o Android, mas acabei "descobrindo" durante o processo que a quantidade de RAM do mini2440 (64M) não é suficiente para este SO. O que o pessoal acabou fazendo foi rodá-lo a partir de um cartão de memória SD usando um mecanismo de swap. Se isso funciona mesmo ou não, veremos no meu próximo post...:)

Um abraço!

Sergio Prado

Posts relacionados:

  1. Mini2440 — Memory layout e bootloader
  2. Kit de desenvolvimento FriendlyARM mini2440
  3. Vídeo: Introdução ao Linux Embarcado

by sergioprado at August 30, 2010 11:00 AM

August 25, 2010

Alberto Fabiano

Leptoniando: Toda computação é sempre física

Seja C, C++, Python, Java, Ruby ou Brainf*ck, independente de sua linguagem preferida, durante a análise léxica, sintática, semântica, geração do código executável ou em qualquer outra operação, na execução de programas, independente da arquitetura de run-time e dependência que ela tenha, seja instruções bare-metal ou dependente de algum sistema operacional, rodando na CPU de [...]

by techberto at August 25, 2010 05:46 PM