Página 1 de 1

Cartao SD

MensagemEnviado: 18 Dez 2012 18:22
por Emilio Eduardo
Boa Noite pessoal,

Estou tentando acessar um cartão microSD de 1 GB. Estou utilizando mikroC e dsPIC.

Preciso acessar na unha para poder fazer o acesso dirigido por interrupções a fim de poder realizar outras coisas enquanto guardo os dados.

Estou ainda na rotina de inicialização, mas não consigo fazer o cartão entrar em modo SPI de jeito algum. A inicialização não precisa ser dirigida por interrupções, uma vez que é feita só uma vez.

Já procurei em vários locais e tudo parece estar correto. De toda maneira aqui vão algumas referências:

http://elm-chan.org/docs/mmc/mmc_e.html
http://www.microchip.com/forums/m530149.aspx
http://www.microchip.com/forums/m429711-print.aspx
http://dlnmh9ip6v2uc.cloudfront.net/dat ... SDSpec.pdf

E o meu código :

Código: Selecionar todos
//============================================================================\\
//                     Rotinas de Comunicação com cartão SD                   \\
//                    Ultima Modificação 17/12/2012 - 19:07                   \\
//                          Por : Emilio Eduardo                              \\
//============================================================================\\

#include "cartao.h"
#include "comunicacao.h"

const car_cmd_spi[6] = {0x40,0x00,0x00,0x00,0x00,0x95};

void car_ConfiguraSPI(){
     TRISBbits.TRISB8 = 0;                                                      //Slave select como saída
     CAR_DESATIVASLAVE;                                                         //CS = 1 (off)
     
     IFS0bits.SPI1IF = 0;                                                       //Limpa flags de interrupção
     IEC0bits.SPI1IE = 0;                                                       //Desabilita interrupção
     IPC2bits.SPI1IP = 2;                                                       //Seta prioridade
     
     SPI1CON1bits.MSTEN = 1;                                                    //Modo Master
     
     SPI1STAT.SPIROV = 0;                                                       //Limpando over-flow
     
     SPI1CON1bits.SPRE = 0b000;                                                 //Prescaler Secundario = 8
     SPI1CON1bits.PPRE = 0b01;                                                  //Prescaler Primário = 16
     
     SPI1CON1bits.DISSCK = 0;                                                   //Clock interno habilitado
     
     SPI1CON1bits.DISSDO = 0;                                                   //Pino SDO1 controlado pelo SPI1
     SPI1CON1bits.MODE16 = 0;                                                   //Comunicação em 8bits
     SPI1CON1bits.SMP = 0;                                                      //Input sampleado no meio do pulso
     
     SPI1CON1bits.CKE = 1;                                                      //Dados na saída mudam no idle-to-active
     SPI1CON1bits.CKP = 0;                                                      //Idle = Low, Active = High
     
     SPI1STATbits.SPIEN = 1;                                                    //SPI habilitado

     IFS0bits.SPI1IF = 0;                                                       //Limpa flags de interrupção
}

void car_IniciaCartao(){
     char i;
     volatile unsigned int temp;
     car_ConfiguraSPI();
     IEC0bits.SPI1IE = 0;                                                       //Desativa interrupções para comunicar ok

     delay_ms(10);

     LATB8_bit = 1;
     
     com_EnviaPacote(1,"Cartao Iniciando1",17,0);
     for(i=0;i<10;i++){
          car_EnviaSPI(0xFF);                                                   //Restarta cartao
     }

     com_EnviaPacote(1,"Ativando SPI",12,0);
     
     LATB8_bit = 0;
     
     for(i=0;i<6;i++){
          car_EnviaSPI(car_cmd_spi[i]);                                       //Seta SPI
     }

     if(car_PedeResposta(0x01) == 1){
          com_EnviaPacote(1,"Cartao nao Iniciado",19,0);
          return;
     }
     com_EnviaPacote(1,"Cartao Iniciado",14,0);
     
     i = 0;

     while((i < 255) && (car_PedeResposta(0x00)==1))                            //Deve continuar enviando comando se houver resposta
     {
          car_EnviaSPI(0x41);                                                   //Envia o comando 1 para retirá-lo do Idle
          car_EnviaSPI(0x00);                                                   //Todos os argumentos sao 1
          car_EnviaSPI(0x00);
          car_EnviaSPI(0x00);
          car_EnviaSPI(0x00);
          car_EnviaSPI(0xFF);                                                   //Checksum nao e mais necessario
          i++;
     }
     if(i >= 254) return;                                                       //Se >= 254 houve um timeout aguardando resposta

     com_EnviaPacote(1,"Cartao saiu do Idle",19,0);
     
     CAR_DESATIVASLAVE;
     
     car_EnviaSPI(0xFF);
     
     CAR_ATIVASLAVE;
     
     car_EnviaSPI(0x10);                                                        //Envia comando para setar comprimento do bloco
     car_EnviaSPI(0x00);
     car_EnviaSPI(0x00);
     car_EnviaSPI(0x02);                                                        //512 bytes
     car_EnviaSPI(0x00);
     car_EnviaSPI(0xFF);

     if((car_PedeResposta(0x00))==1) return;                                    //Se não retornar erro
     
     CAR_DESATIVASLAVE;
     com_EnviaPacote(1,"Configurou Bloco",16,0);
     
     IEC0bits.SPI1IE = 1;                                                       //Ativa interrupções novamente
}

void car_EnviaSPI(char b){                                                      //Envia um byte pela SPI e espera terminar
     volatile char temp;
     SPI1BUF = b;
     while(!SPIRBF_bit){
          asm{
               NOP
          }
     }
     temp = SPI1BUF;                                                            //Le só por ler, para zerar o flag de recebimento
}

char car_LeSPI(char b){                                                         //Envia b, aguarda e devolve a resposta
     char temp;
     SPI1BUF = b;
     while(!SPIRBF_bit){
          asm{
               NOP
          }
     }
     temp = SPI1BUF;                                                            //Lê valor
     return temp;
}

char car_PedeResposta(char b){                                                  //Aguarda por resposta b
     unsigned long contador = 0xFFFF;
     
     while(car_LeSPI(0xFF) != b && --contador > 0);
     
     if(contador == 0) return 1;                                                //Retorna 1 se houve timeout
     else return 0;
}



A parte de EnviaPacote e #include "comunicacao.h" são somente para tentar debugar. Tanto por elas, quanto pelo osciloscopio eu vejo que o cartão não entra em modo SPI.

No osciloscopio o cartão sequer respeita o clock, vive mudando de estado logo em cima da borda de subida do clock, o que não está correto.

Muito Obrigado pela ajuda pessoal

MensagemEnviado: 18 Dez 2012 18:28
por Emilio Eduardo
Acabei de testar, mesmo sabendo que está correto, todas as combinações possíveis de CKP e CKE,nenhum deu resultado.

Valeu pessoal

MensagemEnviado: 18 Dez 2012 18:33
por proex
A inicialização do cartão deve ser feita com clock bem baixo, depois de inicalizado vc pode aumentar o clock da SPI.

.

MensagemEnviado: 18 Dez 2012 20:44
por marcelo campos
Desculpe se vai contra ao que deseja fazer:
tem um projeto pronto da elektor que grava dados recebidos pela serial num pen drive usando pic24 barato, já usei ele e funciona bem
http://www.elektorbrasil.com.br/revistas/2012/maio/registrador-de-dados-usb.2156178.lynkx

também já usei sdcards, mas com pic18 e C18, será que não daria pra adaptar pro que quer um destes stacks FAT em c18, já que do mikroc são fechados ?

Imagem

MensagemEnviado: 18 Dez 2012 21:01
por Emilio Eduardo
Então marcelo, já tinha pensado nessa possibilidade, porém com esse aqui:

https://www.sparkfun.com/products/8627?

O problema é que as duas seriais já estão ocupadas, uma com GPS e outra com um sistema de telemetria. O sistema de telemetria daria muito trabalho para modificar essa altura do campeonato e o GPS talvez seria possível utilizar outro PIC para ler e depois passar por SPI os dados, mas por enquanto não é muito interessante, estamos tentando manter o sistema o mais simples possível nessa primeira versão.

Com relação à parte de FAT, não pretendo utilizar sistema de arquivos, uma vez que o sistema já vai estar no limite com tudo o que ele tem que fazer. Ele vai ter que fazer várias multiplicações devido ao sistema de controle e navegação, o que já vai tomar muito processamento.

Em relação ao clock: O Fcy é de 39542500Hz, com prescaler de 16 e de 8, o resultado é 308Khz, dentro das especificações segundo os manuais.

Claro que depois de inicializar pretendo aumentar, mas por enquanto quero fazer funcionar...

Valeu pessoal!

MensagemEnviado: 18 Dez 2012 21:03
por Emilio Eduardo
Uma dúvida minha é se os resistores de pull-up devem estar somente no MISO ou também no MOSI. Pra mim não faz muito sentido colocar resistor de pull-up no MOSI, mas vai saber..

MensagemEnviado: 19 Dez 2012 12:07
por mastk
Quando o cartão não esta conectado vai ter só ruindo no pino e mesmo quando o estiver, serve para facilitar a comunicação.

MensagemEnviado: 19 Dez 2012 13:18
por pbernardi
Emilio Eduardo escreveu:Uma dúvida minha é se os resistores de pull-up devem estar somente no MISO ou também no MOSI. Pra mim não faz muito sentido colocar resistor de pull-up no MOSI, mas vai saber..


Geralmente vai nos dois, MISO e MOSI. Não se esqueça que são basicamente, TX e RX com outro nome, logo o tratamento dados para as duas linhas são idênticos.

O SCLK geralmente precisa de pull up também. E dependendo da frequência que você trabalhar, o valor de pull up pode influenciar.

Cartão SD

MensagemEnviado: 02 Jan 2013 16:45
por jalves
Vê se pode te ajudar:
CIRCUIT CELLAR Issue 110 September 1999

ou

SanDisk Secure Digital Card
Product Manual
Version 1.9
Document No. 80-13-00169
December 2003

MensagemEnviado: 03 Jan 2013 19:45
por Emilio Eduardo
Muito obrigado pela ajuda pessoal, entrei de férias nesse período e volto dia 14 de janeiro. Apesar disso, já estou olhando os documentos do jalves!

Eu só coloquei os resistores de pull-up no MISO pois no MOSI eu consegui verificar que ele mantém o nível alto e nível baixo nas horas certas. De toda maneira vou colocá-los assim que chegar!

Muito Obrigado a todos.