sexta-feira, 2 de junho de 2017

ESP8266 - Microcontrolador com Wifi e memória Flash

Detalhes sobre o Hardware
O circuito integrado ESP8266 da empresa Expressif é um SoC (System on Chip) bem completo, ele possui portas GPIO, conversor Analígico/Digital de 10 bits, portas PWM, comunicação I²C e SPI, além de uma interface Wifi que implementa o protocolo 802.11 b/g/n com suporte para WPA/WPA2.
O tamanho desse microcontrolador impressiona muito, tem apenas 11,5mm x 11,5mm e depende de poucos recursos externos. Em algumas implementações a antena Wifi é construída como uma trilha na própria placa mas para quem precisa de um alcance maior existe também a opção de uma antena externa.
Sua CPU RISC de 32bits funciona a 80Mhz, bem acima dos microcontroladores existentes nas placas Arduino. O modelo de memória parece um pouco confuso se você não conhece o funcionamento da atualização do firmware. Dentro do microcontrolador existem 3 tipos de memória, 64K de ROM, 96K de RAM e 64K de IRAM (RAM para instruções), essa última memória parece não fazer muito sentido, mas como a CPU foi construída com a arquitetura de Harward sua memória que armazena os programas é diferente da memória que armazena os dados, então essa IRAM possui programas que serão executados e a memória RAM vai ser usada para outras coisas como a pilha e as variáveis dos programas.
Durante o boot o código na memória ROM é executado, ele verifica se o pino GPIO0 está em nível baixo, se estiver então entra em modo de reprogramação e passa a tentar se comunicar via serial com o software de reprogramação, se ele encontrar então vai transferir o novo código para a memória flash. Opa... que memória é essa que eu ainda não havia comentado? Bem, nas placas com o ESP8266 os fabricantes colocam uma memória Flash SPI externa de 512Kb a 4Mb que servirá para armazenar o programa e também dados, quase como se fosse um pequeno cartão SD.
Até aqui tudo bem, entendemos como ele recebe a atualização, mas como o circuito funciona depois do programa ser baixado na memória flash? Basta resetar a placa mantendo o pino GPIO0 em nível alto, em outras palavras, conectando ele ao VCC, dessa forma a rotina na ROM vai entender que é um boot normal, vai copiar o novo programa da memória flash para a memória IRAM e colocar ele para funcionar. Com isso notamos que apesar de existir placas com até 4Mb de flash o limite de IRAM é de 64K.

Detalhes sobre o Software
A Expressif e outras empresas comercializam as placas pelos nomes de suas especificações que vão de ESP-01 até o ESP-14, cada placa com suas particularidades, vamos mostrar apenas algumas, para mais detalhes visite o link do fabricante aqui.
O modelo ESP-01 possui poucos pinos e deixa acesso para o usuário apenas 4 portas, sendo que duas delas são usadas para TX e RX na comunicação serial e as outras duas podem ser usadas normalmente, observando que uma delas é a porta GPIO0 que também é usada para reprogramação durante o boot. O modelo ESP-12 já deixa acesso a todas as portas do microcontrolador, dessa forma ele é bem mais versátil que seu antecessor. Todos os dois utilizam antenas internas, outros modelos possuem recursos diferentes.
O software original disponibiliza uma interface que chamam de interface AT pois utiliza comandos que iniciam pelas letras "AT" da mesma forma que os modens conectados às portas serias dos microcomputadores. Apesar da interface não ser nada amigável, entendemos que ela foi criada dessa forma para atender ao propósito inicial da placa que era servir apenas como uma espécie de placa de rede Wifi para outras placas, como o Arduino. A coisa mudou quando a Expressif disponibilizou o SDK do seu produto na internet e muita gente começou a ver o que era possível fazer com aquele pequeno dispositivo, logo surgiram outras versões de firmwares com interpretadores Lua, Basic e Python além de uma interface com a IDE do Arduino que permite ao usuário programar a sua placa ESP usando a mesma linguagem e ambiente de programação do Arduino com um hardware de melhor performance, menor em tamanho e mais barato (existem sites que vendem a placa por menos de US$ 2,00... isso mesmo menos de dois dólares, eu não escrevi errado).
Apesar do bom trabalho das equipes dos novos firmwares, eles ainda estão em estágio inicial além de que alguns não são compiladores, como o NodeMCU que implementa a linguagem Lua. Nessa arquitetura o seu programa é armazenado na forma de texto em um pseudo filesystem e depois o software interpreta o seu script.
Os recursos desse filesystem e o acesso aos recursos de Wifi que contam com o funcionamento em modo Cliente e modo AP podem ser feitos por meio das bibliotecas fornecidos pelo fabricante, assim como um mini sistema operacional de tempo real chamado RTOS.

Aqui estão as fotos dos modelos ESP-01 e ESP-12 citados no artigo:

ESP-01

ESP-12

Protocolos de Comunicação Serial dos Microcontroladores - SPI, I2C, 1Wire e RS-232

Para que os microcontroladores se comuniquem com outros dispositivos (sejam eles computadores ou outros microcontroladores) podemos usar diversas técnicas, uma das mais simples é usar algum tipo de comunicação serial. Esse nome vem do fato de que os dados são transmitidos bit a bit, por exemplo, se precisamos enviar um byte para outro dispositivo esse byte será enviado um bit por vez e do outro lado os bits recebidos vão recompor o byte transmitido. Parece simples, não é mesmo? Infelizmente o mundo real não é tão bonito assim... para que isso funcione precisamos considerar um monte de outras coisas como ruídos na transmissão, a frequência com que os dados serão enviados, o sincronismo dessa frequência dos dois lados, os limites de inicio e fim de transmissão/recepção e muitos outros.
É possível implementar tudo isso por software? Claro que sim. Mas além de dar um bocado de trabalho teríamos que implementar nossa solução nos vários tipos de hardware que vão usar. Para nossa sorte os microcontroladores mais comuns do mercado já possuem recursos implementados em hardware ou na forma de bibliotecas e a maior vantagem é que eles seguem certos padrões chamados protocolos de comunicação que permitem a comunicação com dispositivos que implementem o mesmo protocolo.
Vamos mostrar a partir daqui quais são os mais comuns no ambiente dos microcontroladores. Neste artigo eu não vou comentar sobre comunicação de rede, mesmo que existam algumas implementações de rede ethernet que, no fim das contas, é um barramento serial, mas foge completamente da simplicidade que quero demonstrar.

Protocolo 1-Wire
Como o nome sugere, esse protocolo usa apenas um fio. Mas isso não é BEM a verdade, ele usa um fio para dados, mas usa também o aterramento ou GND, ou seja, já são dois fios. Em algumas implementações vocês verão o dispositivo usando um terceiro fio para a alimentação, geralmente de 5v, apesar de ser possível utilizar com apenas dois no modo "vampiro". Nesse modo o dispositivo usa a energia que vem na linha de dados e faz uso de um capacitor para continuar alimentado nos períodos em que o sinal de dados fica baixo. O protocolo prevê a existência de um dispositivo Mestre na rede que é chamada de Microlan, os outros dispositivos funcionam no modo Escravo. O dispositivo Mestre envia um comando para que os escravos se identifiquem e inicia a comunicação com cada um deles. Cada dispositivo 1-Wire possui um número único que o identifica.
Exemplo: Termômetro DS18B20 da Dallas Semiconductor.

Protocolo I²C
O nome do protocolo vem de Inter-Integrated Circuit, é permitido o uso de vários Mestres no mesmo barramento e um limite teórico de 127 Escravos. O protocolo usa 2 sinais só para controle, além da alimentação dos circuitos, esses sinais são identificados como SDA (Serial DAta) e SCL (Serial CLock), as duas linhas devem ser ligadas ao VCC por meio de resistores pullup de 1,5KOhms.
O SCL é usado para dar o ritmo da comunicação, isso garante o sincronismo e a exatidão dos pulsos já que transmissor e receptor usam o mesmo sinal de controle. A linha SDA vai portar o dado transmitido/recebido, essa é uma linha bidirecional, ou seja, em certos momentos ela envia e em outros ela recebe dados.
Exemplo: Serial EEPROM 24LC01 e Serial EEPROM AT24C256

Protocolo SPI
O Serial Peripheral Interface ou SPI é outro protocolo serial síncrono assim como o I²C, uma grande diferença é que ele utiliza linhas específicas para transmissão e recepção de dados.
O SPI precisa de 4 sinais de controle nos dispositivos Escravos, no dispositivo Mestre será necessário 3 sinais de controle mais um para cada Escravo que ele vai controlar. Os sinais do protocolo são MISO (Master Input Slave Output) que recebe no Mestre os dados vindo de um Escravo, MOSI (Master Output Slave Input) que o Mestre usa para enviar dados a um Escravo, SCLK (Serial CLocK) que gera o sincronismo para a rede, assim como faz o SCL no I²C e por último o sinal SS (Slave Select) que nos Escravos é uma porta de entrada onde ele recebe um sinal do Mestre indicando que ele está habilitado, caso esteja desabilitado o Escravo deve ignorar o tráfego no barramento. No mestre existem tantos sinais SS quantos forem os escravos, cada um estará ligado a um Escravo e será usado para habilitar esse escravo para uso do Barramento.
Exemplo: Cartões SD

Protocolo RS-232
Esse protocolo foi padronizado em 1969 e ainda está em uso, foi muito utilizado nos ambientes dos antigos mainframes e para comunicação com dispositivos periféricos como modens e impressoras.
O problema de usar esse tipo de protocolo é que os sinais variam entre 3v a 15v positivos ou negativos de acordo com a situação e essa tensão está muito longe do que suportam os microcontroladores que, na maioria, trabalham com 5v ou até mesmo 3,3v. Para permitir que seja utilizado foi feita uma modificação nos sinais criando o que chamam de RS-232 TTL, que é o mesmo protocolo mas com tensões no mesmo nível dos circuitos TTL, ou seja, de 0v até 5v.
Para se comunicar com dispositivos RS-232 nativos os microcontroladores precisam usar um circuito integrado que faça a conversão dos sinais, este circuito se chama MAX232, ele consegue realizar a conversão dos sinais de um padrão para o outro.
Caso os dois dispositivos trabalhem em nível TTL eles podem ser ligados diretamente um ao outro. Este protocolo trabalha ponto a ponto, em outras palavras, só existem dois dispositivos envolvidos e o modo mais simplificado de uso, que é aquele usado nos microcontroladores, prevê a utilização de apenas dois sinais, TX (Transmissão) e RX (Recepção). O TX de um dispositivo é conectado ao RX do outro e vice versa, e eles se comunicam por meio desse protocolo assíncrono.
Exemplo: Modem

Portas Analógicas nos Microcontroladores - ADC e PWM

Vamos falar um pouco sobre portas analógicas tanto de entrada como de saída, para isso temos que entender o que é um sinal analógico e como podemos ler esse sinal.
Um valor digital (ou binário) só possui dois estados que podem ser considerados como 0 e 1 ou ligado e desligado ou alto e baixo, etc. Esse valor quando é lido de uma porta digital só consegue nos retornar uma dessas duas informações discretas. No artigo sobre GPIO eu comentei que várias portas digitais podem ser combinadas para que em uma única operação sejam lidos vários bits simultaneamente, essa afirmação é verdadeira mas temos que perceber que cada bit é um sinal independente, mesmo que no final faça parte de um mesmo dado, por exemplo, quando 8 entradas digitais são lidas por uma porta como um conjunto de 8 bits, ou seja, um byte.

Portas analógicas de entrada
Nos sinais analógicos de entrada os valores podem oscilar entre os limites mínimo e máximo que a porta consegue captar, se ela consegue ler tensões entre 0v e 5v então a tensão aplicada no pino da porta será convertida para um valor digital que poderá ser tratado pelo software. Para fazer isso o microcontrolador se utiliza de um circuito chamado de Conversor Analógico/Digital (ou ADC que significa Analog/Digital Converter), existem diversas formas de funcionamento desses conversores, não entraremos em detalhes por enquanto mas no momento só precisamos saber qual é a sua "resolução" ou qual o número de bits que esse conversor possui. Um conversor de 8 bits consegue ler valores entre 0 e 255 (o máximo de valores é calculado pela fórmula 2 elevado ao numero de bits, como são 256 valores, temos de 0 a 255), então uma tensão 0v na entrada apresenta um valor 0 na porta e uma tensão de 5v apresenta 255 quando é feita a leitura. No Arduino o ADC possui 10 bits retornando assim valores entre 0 e 1023. É possível usar um ADC externo com resoluções maiores.

Portas analógicas de saída
Não é comum que os microcontroladores possuam Conversores Digital/Analógico (DAC), um circuito desse tipo é muito específico e poderia ser usado, por exemplo, para reproduzir músicas pois essa é a base para geração de sons analógicos a partir do armazenamento digital. Mas existe um outro tipo de saída que não é analógica mas que pode, com certas restrições, ser usada com esse propósito. Esse tipo de saída se chama PWM (Pulse With Modulation), esse é um padrão usado por diversos dispositivos como, por exemplo, os servo-motores que se valem desse padrão para que o circuito possa controlar o ângulo em que o servo deve se posicionar.
O PWM gera uma saída com uma frequência fixa onde cada ciclo ocorre em 2 milissegundos, durante esse período o sinal fica parte do tempo em nível alto e parte em nível baixo, ele é um sinal de onda quadrada, não é uma onda senoidal. A frequência é fixa mas podemos controlar por quanto tempo a onda ficará em nível alto e isso é proporcional ao valor que gravamos na porta de saída. No Arduino os pulsos PWM são controlador por meio de um valor de 8 bits, então se usamos o valor 127 a onda vai ficar 50% do tempo alta e 50% do tempo baixa, se diminuímos o valor o tempo de onda alta também diminui e isso pode ser usado, por exemplo, para controlar o brilho de um LED pois quanto mais tempo em nível alto, mais claro o LED vai ficar.
Tudo bem, já percebemos que isso não é nem de longe uma saída analógica, mas como no caso do exemplo com o LED, ele pode funcionar de forma parecida.
Abaixo está a imagem do funcionamento dos pulsos PWM obtida do site do Arduino.



GPIO nos microcontroladores: Uma porta para o mundo externo

GPIO - General Purpose Input/Output

As "Portas" em um microcontrolador e até mesmo em um microprocessador funcionam como uma passagem de informação entre o mundo interno desses dispositivos e o meio externo, são mapeadas por meio de endereços como as memórias e, de fato, em algumas arquiteturas as portas são acessadas como se fossem posições de memória mesmo, mas em outras elas são acessadas por meio de instruções específicas.

Nesse artigo vamos explorar as portas digitais, mas falarei sobre as portas analógicas em outro artigo, vamos começar pelas portas digitais de 1 bit que podem conter apenas uma informação lógica verdadeiro/falso, sim/não, 0/1, ligado/desligado ou qualquer abstração que você possa imaginar.

Portas de Saída
Quando o dispositivo precisa acessar enviar sinais para fora ele utiliza uma porta de saída, dessa forma a informação armazenada na porta se materializa na forma de um sinal digital em um determinado pino do circuito integrado. Para exemplificar, imagine que estamos trabalhando com um circuito que utiliza a tensão de 5v, quando gravamos o valor 0 (zero) na porta de saída teremos no pino do chip relativo à essa porta a tensão 0v, quando gravamos o valor 1 (um) a saída passa para 5v. Essa tensão pode variar um pouco de acordo com o chip mas essa variação não deve ser significativa, na descrição da porta de saída vamos falar sobre os limites aceitáveis.

Portas de Entrada
Para obter um dado do meio externo fazemos o processo inverso, lemos o valor de uma porta de entrada e teremos um bit 0 ou 1 de acordo com a tensão aplicada no seu respectivo pino do circuito integrado, no caso das entradas a tensão deveria ser 0v ou 5v, certo? sim, deveria, mas na prática não é exatamente assim pois como poderíamos tratar um valor de 2,5v? ele está no meio do caminho.
Para solucionar o problema as portas possuem limites para identificar essas tensões de entrada, esses valores variam um pouco de acordo com a tecnologia usada, você consegue essas informações no datasheet do circuito, só para se ter uma ideia os circuitos TTL identificam como 0 as tensões entre 0.0v e 0,8v e identificam como 1 as tensões entre 2.0v e 5.0v, já na tecnologia CMOS essas faixas ficam respectivamente entre 0.0v e 1.5v para o valor 0 e 3.5v a 5.0v para o valor 1.
Então pensamos, existe um buraco nessa faixa de valores possíveis entre 0v e 5v, não é mesmo? O que acontece quando uma tensão está dentro dessa faixa indeterminada? Exatamente isso, o valor a ser considerado será também indeterminado, ou seja, pode ser 0 ou 1, não há nenhuma garantia.

Existem portas digitais com mais de 1 bit? Sim, claro, mas cada bit está conectado à uma linha externa, ou seja, é como se fossem várias portas de 1 bit em paralelo. De fato a porta paralela (hoje em dia muito raro de se encontrar nos PCs) funciona em parte dessa mesma forma e pode ser usada como uma porta de saída de 8 bits, ao gravar um byte os valores de cada bit afetam as linhas na saída.

No acrônimo GPIO do título desse artigo o termo "General" significa que é uma porta de uso geral, ou seja, não foi criada com uma função específica de entrada ou saída e pode ser configurada para uma dessas duas formas de funcionamento via software, ou seja, antes de começar a usar uma porta GPIO devemos configurar se ela vai se comportar como uma porta de entrada ou saída.

Já comentei que não podemos deixar um valor na faixa indeterminada para que possamos garantir a informação que vamos usar, observe a figura abaixo como foi conectado um interruptor e podemos ler o valor da porta para saber se ele está aberto ou fechado.


Observe que o interruptor pode estar aberto ou fechado, de um lado ele se liga a porta de entrada e de outro se liga ao VCC (tensão de trabalho, que geralmente é de 5v). Com esse esquema a tensão VCC é conectada à porta de entrada quando o interruptor é acionado e podemos ler o valor na respectiva porta. Tudo certo não é mesmo? Nem tanto... quando o interruptor está aberto o pino da porta de entrada não está ligado à nenhuma tensão e acaba ficando em um estado indeterminado, qualquer interferência poderia fazer com que uma tensão apareça nessa porta e faça um acionamento indevido.
Como solucionar essa situação? A resposta é simples, usando um resistor "pulldown", esse resistor é ligado entre a porta e o GND (Terra ou 0v) assim quando o interruptor está aberto garantimos o valor 0 e quando fechado boa parte da tensão do VCC passa até a porta de entrada pois o resistor "dificulta" a sua passagem para o GND, esse resistor força a porta a ficar no estado baixo. Se for interessante inverter a lógica, podemos usar um resistor "pullup" ligando a porta a um resistor e este no VCC, isso força a porta a ficar em nível alto, o interruptor se liga na porta e do outro lado no GND. Veja na imagem abaixo os dois exemplos.


Nos próximos artigos vamos ver como funcionam as portas analógicas.