terça-feira, setembro 23, 2014

Usando Cartões SD com o Arduino- Parte 1

Os cartões SD são um meio de armazenamento de grande capacidade e bastante compacto (principalmente na versão microSD). Vejamos, de forma sucinta, como utilizá-los com o Arduino.


A Interface e Organização dos Cartões SD

A wikipedia e esta página descrevem a interface dos cartões SD. Embora existam formas mais rápidas de comunicação, no Arduino normalmente se utiliza o modo SPI. Neste modo é usada uma comunicação serial padrão SPI (sinais MOSI, MISO, SCK e CS). Os cartões SD são bastante inteligentes, cuidando internamente de detalhes como correção de erros e a distribuição do uso (como toda memória Flash, os cartões SD possuem um limite de apagamentos e escritas)

Do ponto de vista elétrico, os cartões SD trabalham com 3.3V. Modelos mais recentes permitem ao software alterar a tensão para 1.8V, mas vamos ignorar isto.

Os cartões SD simulam blocos de 512 bytes independente da estrutura interna da Flash. No nível mais baixo, usamos comandos para ler e escrever estes blocos. Os blocos são endereçados sequencialmente, usando endereços de 32 bits.

A especificação determina o uso do formato FAT. Neste formato, alguns blocos no início contém uma tabela (a FAT - File Allocation Table) que indica quais blocos estão vazios e quais estão alocados. Os blocos alocados a cada arquivo são encadeados na FAT em uma lista ligada. Diretórios guardam os nomes dos arquivos e subdiretórios, o bloco inicial, o tamanho em bytes e a data e hora da última atualização. O diretório raiz ocupa blocos específicos no início; os subdiretório são alocados da mesma forma que arquivos.

Usando um Cartão SD com o Arduino: Hardware

Do ponto de vista de hardware, basta alimentar o cartão SD (com 3.3V) e ligar os quatro sinais de comunicação. Entretanto, como o Arduino trabalha (normalmente) com 5V, é preciso adequar os sinais que saem do Arduino e entram no SD (MOSI, SCK e CS). O sinal MISO pode ser ligado direto, pois o Arduino não terá problemas em reconhecer os níveis lógicos alto e baixo de um sinal de 3V. Embora seja possível implementar "na raça" o SPI, com qualquer conjunto de pinos digitais do Arduino, é mais eficiente usar a interface SPI interna do ATmega. No Arduino UNO, isto corresponde a ligar MOSI em D11, MISO em D12 e SCK em D13 (no Arduino Mega os pinos são outros). Por compatibilidade com o shield Ethernet, é costume usar D4 como CS.

A interface SPI do ATmega tem uma peculiaridade no que diz respeito ao sinal CS (chamado de SS na documentação) quando operado no modo Master.  Se o sinal SS for configurado como entrada, um nível baixo neste pino forçará o modo Slave. Se o sinal SS for configurado como saída, poderá ser usado normalmente sem interferir no funcionamento do SPI. No Arduino o pino SS corresponde ao D10.

Existem alguns shields específicos para SD, entre os quais a shield Ethernet (o modelo com W5100). Como o meu interesse era apenas salvar dados no SD, o shield Ethernet me pareceu um exagero. Eu usei uma plaquinha simples de interface (comprada na DX, mas você acha algo semelhante em outros locais). Esta placa tem até um regulador para reduzir a alimentação de 5V para 3.3V, porém não adapta o nível dos sinais de comunicação.



Encontrei um instructable que usa exatamente a mesma plaquinha, montada em uma placa proto shield (como a que vimos por aqui). Um integrado 4050 é usado como conversor de nível (o que fica anotado como sugestão para outras situações parecidas). Eis o esquema de montagem:



Se você for seguir o instructable, atenção que tem fotos de várias montagens diferentes misturadas. Eu preferi soldar os fios por baixo da placa, sem colocar conectores para ligar outras coisas no shield. Depois de montado, percebi que o posicionamento da plaquinha do SD atrapalha o acesso às entradas analógicas; teria sido melhor montá-la virada de 90 graus. Para fins de teste, coloquei no shield um sensor de temperatura LM35 na entrada A0.



Uma ideia interessante, mas que não implementei por enquanto, é colocar um relógio de tempo real para poder marcar com precisão a data e horário das informações registradas. Um DS1302 com uma bateria backup de NiCad (com aqui) seria uma boa pedida.

No próximo post vamos ver o software necessário.

2 comentários:

Fabio Rocha disse...

Ola,

Recentemente fiz alguns estudos com acesso a memorias SD com um microcontrolador AVR. Achei muito interessante o artigo que foi publicado no seu blog. Tenho uma pequena contribuição.

1) Os cartões de memoria funcionam a 3.3v tanto a sua alimentação quanto seus pinos de dados. Violar esse valor pode danificá-lo.

2) Existem vários esquemas na internet que usam resistores para fazer um divisor de tensão e assim converter 5v (nível alto dos pinos digitais do arduino) em aproximadamente 3.3v além de usar um regulador de tensão para prover os 3.3v para a alimentação da memória. O pino de SO não precisa de conversão pois é o pino de resposta da memoria e mesmo que este tenha nível alto (3.3v) seria interpretado como nível alto pelo microcontrolador.

3) Algum circuitos (tal como o que aparece na foto no seu artigo) não usa resistores como divisores de tensão. Na verdade, o esquema da placa usa resistores de pullup de 10k forçando para o nível 3.3v. Essa placa NAO deve ser utilizada da mesma forma que o circuito que usa divisores de tensão pois fará que os pinos de SCK, SI, CS fiquem proximos de 5v, violando as especificações da memoria.

Para um circuito como o da placa temos que pensar assim. Se desejamos colocar um pino ex: SCK em 3.3 v devemos desconectar eletricamente o pino digital do arduino do circuito, assim, os 3.3v seriam fornecidos através do resistor de pullup. Se desejamos colocar o pino SCK em aproximadamente 0v (nível baixo) devemos fazer que a corrente seja drenada para dentro do chip e assim a memória perceberá um nível baixo (próximo de 0v da linha).
Seria como se estivessemos simulando uma porta com saída em coletor aberto.

O código para controlar os pinos seria
algo assim:

void clk_alto (void)
{
// resistencia alta na entrada do chip
pinMode(PIN_CLK, INPUT);
}
void clk_baixo (void)
{
// a porta operando como saida e com valor nivel baixo funciona como um dreno de corrente.
pinMode(PIN_CLK, OUTPUT);
digitalWrite(PIN_CLK,LOW);
}

Ou seja, se o sujeito escrever o código sabendo como a placa foi feita, não precisará de CIs auxiliares para converter o nível de tensão dos pinos. Tudo pode ser resolvido por sofware.

Daniel Quadros disse...

Boa, não tinha pensando na possibilidade de usar as portas digitais para simular coletor aberto. Com a relação ao uso de divisores resistivos, eu já fiz isto com o display Nokia 5110.