sexta-feira, agosto 31, 2007

Desenvolvendo Software para Sistemas Embarcados

Um dos motivos dos posts estarem ficando espaçados são alguns problemas que tenho enfrentado no desenvolvimento de software para um par de sistemas embarcados. São dispositivos baseados em micro-controladores e além, das dificuldades normais de software, existe sempre a possibilidade de um problema no hardware (no projeto ou na montagem).

Embora não possa entrar nos detalhes (para não comprometer a confidencialidade do meu cliente), existem alguns pontos que dá para compartilhar com a minha dupla de leitores habituais.

Circuito de Baixo Consumo

Os dispositivos para os quais estou escrevendo software são alimentados a bateria não recarregável e o consumo precisa ser bastante baixo para garantir uma duração de meses a anos.

São necessários vários cuidados para reduzir o consumo. Por exemplo, é comum a presença nos circuitos de vários resistores ligados entre um pino do micro-controlador e terra ou a alimentação (como os famosos pull-down e pull-up para garantir o nível do sinal quando ninguém mais está colocando um sinal no circuito), estes resistores precisam ter valor elevado e, sempre que possível, o micro-controlador deve colocar no pino o mesmo sinal que na outra ponta do resistor.

Os micro-controladores costumam possuir diversos modos de operação, permitindo desligar parte do circuito interno para economizar bateria. No caso do micro-controlador usado em um dos dispositivos, o modo mais econômico desliga tudo exceto a memória. Para chegar à autonomia de anos é preciso manter o micro-controlador dormindo a maior parte do tempo. Se, por exemplo, em cada segundo executar por 5 ms com consumo de 10 mA e ficar dormindo o resto do tempo com consumo de 1 uA (microAmpere), uma bateria alcalina de 1000mAh vai durar mais de 2 anos.

O único jeito de acordar este micro-controlador é gerando um sinal de reset através de um circuito externo (no caso um timer de baixíssimo consumo e alguns sensores). Desta forma o reset passa a ser parte normal da operação, o que torna o software um pouco estranho. Como conseqüência, é preciso distinguir o reset de acordar do reset real (o power-on). Como a memória Ram é mantida mesmo com o processador parado, isto não é muito complicado.

O problema é como forçar um power-on. Como o consumo do micro-controlador dormindo é baixíssimo, a energia contida nos capacitores do circuito é suficiente para manter a Ram por muito tempo. A simples conexão da minha serial de debug consegue manter o circuito funcionando.

Pinos em Aberto

Falando em resistores de pull-up e pull-down, tive um par de problemas sérios num outro projeto onde alguns destes resistores foram esquecidos na montagem.

Neste caso o nível destes pinos fica indefinido. Pior ainda, ele acaba sendo influênciado pelos sinais próximos. Em um dos casos era um teclado em matriz, onde você coloca um sinal nas linhas, lê o resultado nas colunas e descobre quais teclas estão apertadas. Uma das colunas estava sem o resistor e a leitura quando não tinha tecla apertada acabava dependendo do que estava sendo colocado nas linhas. Sem entender direito o que estava acontecendo, eu acabei alterando a minha rotina de varredura até achar uma forma na qual (por acaso) eu conseguia ler sempre o valor correto na coluna.

Depurando Sem Serial

No segundo dispositivo é usado um micro-controlador muito simples e de baixo custo. Tão simples, que nem UART tem. Para fazer comunicação serial, é preciso ficar subindo e descendo por software o sinal de um pino para cada bit (com o timing correto). Para complicar, a memória de programação lotou rapidamente. O micro-controlador tem capacidade de depuração in-circuit, porém o código gerado para debug era grande demais. O que sobrou para debug foi um led e um pino livre do processador.

A minha principal ferramenta de debug foi um osciloscópio. O modelo disponibilizado pelo cliente não possui tela, ele é usado conectado a um PC, o que permite gravar imagens das formas de onda.

No início foi meio estranho, mas este tipo de depuração tem a vantagem de permitir ver graficamente o andamento do software ao longo do tempo. Como o osciloscópio tem dois canais, dá para ver a relação entre acontecimentos assíncronos. E é claro que dá para medir com precisão o tempo entre eventos.

Existe mais entre o VCC e o Terra que se possa imaginar

Quando estamos programando em baixo nível, pensamos muito em binário: é 0 ou 1. No hardware, entretanto, existe muita coisa entre o 0 e 1 (e às vezes até fora dele).

Um dos bugs mais complicados foi a perda esporádica da Ram no reset, no dispositivo onde isto não devia ocorrer. Esporádica quer dizer: às vezes ocorre seguidamente em um minuto e em outras fica horas sem ocorrer. Perda quer dizer que algum bit na Ram virava.

Após vários dias penando, apelei para o osciloscópio e observei o sinal ao lado no reset. À primeira vista, parece normal, porém a curva de subida me pareceu muito longa. Conversando com o projetista do hardware descobri que um capacitor estava acidentalmente com valor errado (um erro de digitação); arrancando o infeliz o sinal passou a subir "instantaneamente" e o problema subiu.

Aparentemente a subida gradual do sinal ocasionalmente confundia o processador. Algo parecido com a execução paranormal de código.

Um comentário:

Anônimo disse...

Olá, DQ!

Acho muito interessante esse mundo dos circuitos e microcontroladores. Um dia eu chego lá. Por enquanto, sacio minha curiosidade lendo seus artigos sobre o assunto.

Por falar em curiosidade, fiquei curioso quando você disse "dupla de leitores habituais". Quer dizer, se são dois, pode me incluir na lista =).

[]s