Autor Tema: Comenzando con memorias SD/MMC. Librería a nivel hardware.  (Leído 158454 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado omix

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 244
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #210 en: 07 de Octubre de 2013, 15:37:10 »
Hola,
los síntomas que comentas parece como si no estuviera el SPI en modo 0,0, es decir, CKE = 1, CKP = 0. Algo similar me ocurrió a mi, y era porque lo tenia configurado con CKE = 0 y CKP = 0, hacia que a veces leyera bien y otras no, pero en cuanto me di cuenta de eso empezó a funcionar correctamente siempre.

Un saludo.

Desconectado cosmic

  • PIC16
  • ***
  • Mensajes: 175
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #211 en: 07 de Octubre de 2013, 16:41:14 »
Es bastante raro, yo use las librerias de suky y logre escribir y leer las cuatro marcas de memorias que tenia a mano :-/

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #212 en: 07 de Octubre de 2013, 17:10:42 »
Omix, gracias por tu repuesta.

Algo de eso pensé que podría ser, pero ya a estas alturas estoy super mareado  :5].

He leído en varios lados y las SD /MMC soportan modos 0 y 3. Tengo en el CCS el MODE=0, pero cuando mido en el osciloscopio, el clock posee un cero para el idle. Cuando pruebo el MODE=3, el clock posee un idle de uno. Buscando en internet, las tablas dicen lo contrario, justo al revés. Entonces, me podrías aclarar, si no es molestia, cómo debería estar el clock y en qué flanco se leería?? Porque de ser esto que está mal, por qué sale todo OK, menos los datos??

Cosmic, qué versión de CCS usaste?? Me podrías pasar un rar con la librería tal cual la tienes así la pruebo??

Saludos!!

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #213 en: 07 de Octubre de 2013, 17:24:21 »
Un detalle, que no ha de ser para menos.

Con la librería de suky, obtenía lo que puse más arriba, en una memoria Nokia de 128MB. Con la librería del CCS, la mmcsd.c y la misma memoria, obtengo esto:





Inicializando Memoria

Comando CMD0...OK - 0
Comando CMD1...OK - 153
Comando CMD55...R1 = 0
Comando ACMD41...R1 = 4
Comando CMD16...OK - 0
Comando CMD E/D CRC...OK - 255
Comando CMD17...OK - 0
Esperando Token...OK

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03
02 00 06 07 E0 C0 61 00 00 00 9F C0 03 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA



Por lo que se ve, se puede leer prácticamente lo mismo. Podrá ser algún problema con la versión del compilador?? Porque con el WinHex, esta memoria tiene contenido en la dirección 0x00000000.

Ahora voy hacer la misma prueba de los dos códigos con la memoria SanDisk de 4GB.

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #214 en: 07 de Octubre de 2013, 17:31:03 »
Bueno, este es el resultado con los dos códigos, pero con una SanDisk.

librería Suky




--> Se inicia sincronizacion

--> Se envia CMD0 (Se desactiva SD Card)

Repuesta al ultimo CMDxx : 1)

--> Se envia CMD1 (Se activa SD Card)



Librería mmcsd.c del CCS:




Inicializando Memoria

Comando CMD0...OK - 0
Comando CMD1...1



Como se puede observar, ambas se clavan en el CMD1, apenas se trata de inicializar. En el caso del código mmcsd.c, le agregué que si sale por timeout, me diga cuál fue el el útlimo R1 que recibió. Claramente, el CMD1 responde 0x01, para la SanDisk.

Al parecer no me va a quedar otra que comprar una SD de otra marca, para comprobar de dónde proviene el error.

Ya es bastante info, o por lo menos no estamos navegando a ciegas. Estos últimos resultados han dado un par de posibilidades más de por qué, con la memoria de Nokia, leo lo que leo. Tal vez sea por falta de algún comando o cosa propia de la marca.

Saludos

Desconectado Suky

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #215 en: 07 de Octubre de 2013, 20:11:31 »
Hola! Probaste de escribir el sector y después leerlo? Y eso mismo mirarlo con el WinHex?


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado omix

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 244
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #216 en: 08 de Octubre de 2013, 16:31:34 »
Omix, gracias por tu repuesta.

Algo de eso pensé que podría ser, pero ya a estas alturas estoy super mareado  :5].

He leído en varios lados y las SD /MMC soportan modos 0 y 3. Tengo en el CCS el MODE=0, pero cuando mido en el osciloscopio, el clock posee un cero para el idle. Cuando pruebo el MODE=3, el clock posee un idle de uno. Buscando en internet, las tablas dicen lo contrario, justo al revés. Entonces, me podrías aclarar, si no es molestia, cómo debería estar el clock y en qué flanco se leería?? Porque de ser esto que está mal, por qué sale todo OK, menos los datos??

Efectivamente las tarjetas SD técnicamente soportan ambos modos el 0 y 3, aunque yo personalmente uso siempre el 0 porque casi todos los dispositivos que utilizo usan este modo y si pongo varios en el mismo bus SPI no tengo que andar cambiando de modo. En ambos modos el dato se pone en el flanco descendente y se lee en el ascendente, la única diferencia está en el estado en reposo de la señal de reloj, en el caso de modo 0 se mantiene a 0 y en modo 3 se mantiene a 1.

Saludos.

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #217 en: 08 de Octubre de 2013, 17:12:33 »
Gracias nuevamente.

Suky, no se cómo me serviría esa prueba ya que, para iniciar el FAT, es necesario leer el primer sector de la SD. Si yo trato de escribir y luego leer lo que escribí, no gano nada. Seguiría sin poder leer la 0x00000000.

Omix, gracias por tu aclaración. Entonces me quedo tranquilo en que el modo, esta OK.

Ahora estuve probando con una micro SD Kingston de 4GB, la cual leí con el WinHex y he obtenido una serie de datos interesantes. Realizando los comandos CMD0 y CMD1 sin deshabilitar la SD, con dos de las memorias me mostraba lo mismo que les mostré antes. Cuando habilito y deshabilito en cada comando, en de ellas me muestra lo mismo que antes. Se el caso que sea, la Kingston no da señal de vida, se clava en la espera de la repuesta del CMD1.

Esto me tiene como loco  :5], no puede ser que no se pueda leer la tabla de la SD. Leo y leo por internet, y a todos los que les anda, tienen de los más variados métodos de inicialización. y ninguno tiene nada parecido al otro, salvo por el CMD0.

Se me queman los libros, ya.... je...

Desconectado Suky

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #218 en: 08 de Octubre de 2013, 20:56:47 »
Suky, no se cómo me serviría esa prueba ya que, para iniciar el FAT, es necesario leer el primer sector de la SD. Si yo trato de escribir y luego leer lo que escribí, no gano nada. Seguiría sin poder leer la 0x00000000.


La prueba sería sin sistema de archivos, para  probar el acceso a bajo nivel.


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #219 en: 09 de Octubre de 2013, 15:32:34 »
Suky, entiendo lo que me decís. Ahora lo voy a probar. De todo modos, no me termina de cerrar porque me pregunto qué razón haría que se lea lo que escribí, si ni siquiera lee lo que trae la memoria. Pero ya te comento que sale.

Por otro lado, he probado una librería de un Brasilero, que anduvo perfecto con las MMC y SD viejas. Leoo perfecto el primer sector, el cual contiene la información de la FAT  :-/ :-/. La librería es esta:




Código: [Seleccionar]
/**********************************************
 * ANDRE L. V. SILVA
 * andreluizeng@yahoo.com.br
 *
 * change the strings to your own language if you want (it is in portuguese br)
 *
 * Example of use:
 *
 *
   int main (void)
   {
      pic initialization....

      InicializaSPI ();
      InicializaMMC ();
      InicializaFAT32 ();

      While (TRUE)
      {
         your code ....
      }

      return 0;
   }

 **********************************************/
 
#include "MMCFat32.h"
#include "string.h"

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Funções do cartão MMC
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------

int32 FATTable[128];
int32 gFirstEmptyCluster;
FAT32Vars gFAT32Vars;
diskinforec DiskInfo;
FILE gFiles[MAXFILES];


#byte MMCAddressL       = gFAT32Vars
#byte MMCAddressH       = gFAT32Vars+1
#byte MMCAddressHL       = gFAT32Vars+2
#byte MMCAddressHH       = gFAT32Vars+3
#byte gStartSectorL    = gFAT32Vars+8
#byte gStartSectorH    = gFAT32Vars+9
#byte gStartSectorHL    = gFAT32Vars+10


//-------------------------------------------------------------------------
// Detecção do MMC 
//-------------------------------------------------------------------------
char DetectaMMC (void)
{
   char Resp;
   
   TRIS_DETECTA_MMC = ENTRADA;
   
   printf ("\r\nDetectando MMC...");
   
   if (MMC_DETECT)
   {
      printf ("Nao Conectado !");
      printf ("\r\nAguardando Conexao... ");
       
      while (MMC_DETECT);
   }
   
   TRIS_DETECTA_MMC = ENTRADA;
   MMC_DETECT = SAIDA;
   MMC_DETECT = FALSE;
   
   
   printf ("OK");   
   
   return Resp;
}   

//-------------------------------------------------------------------------
// Configuração da SPI
//-------------------------------------------------------------------------
void InicializaSPI (char Tipo)
{
   TRIS_SPI_SCK      =   SAIDA;
   TRIS_SPI_SDI      =   ENTRADA;
   TRIS_SPI_SDO      =   SAIDA;
   TRIS_SPI_MMC_CS      =   SAIDA;

   MMC_CS   = TRUE;
   SPI_SCK = TRUE;
   SPI_DI   = TRUE;
   SPI_DO   = FALSE;

    if (Tipo == MAXIMO)
   {
      printf ("\r\nAjustando SPI: ");
      printf ("5 MHz...");
     
      SSPEN = FALSE;
      SSPCON1 = SPI_MASTER_SCK_DIV_4;
      SMP = TRUE;
      CKE = FALSE;
      CKP = TRUE;
      SSPEN = TRUE;
   }


   else if (Tipo == MEDIO)
   {
      printf ("\r\nAjustando SPI: ");
      printf ("1.25 MHz...");
     
      SSPEN = FALSE;
      SSPCON1 = SPI_MASTER_SCK_DIV_16;
      SMP = TRUE;
      CKE = FALSE;
      CKP = TRUE;
      SSPEN = TRUE;

   }

   else if (Tipo == MINIMO)
   {
      printf ("\r\nInicializando SPI: ");
      printf ("312.5 KHz...");
     
      SSPEN = FALSE;
      SSPCON1 = SPI_MASTER_SCK_DIV_64;
      SMP = TRUE;
      CKE = FALSE;
      CKP = TRUE;
      SSPEN = TRUE;
   }

   printf ("OK");

   delay_ms (10);

    return;
}



//-------------------------------------------------------------------------
// Função de Seleção do CS do MMC
//-------------------------------------------------------------------------
void SelecionaMMC (boolean Flag)
{
   if (Flag)
   {
      MMC_CS = FALSE;
   }

   else
   {
      MMC_CS = TRUE;
   }
}


//-------------------------------------------------------------------------
// Função para enviar um dado via SPI
//-------------------------------------------------------------------------
void EnviaMMC (char a)
{
   char b;

   BF = FALSE;
   SSPBUF = a;
   while (! BF);
   b = SSPBUF;

   return;
}

//-------------------------------------------------------------------------
// Função para receber um dado via SPI
//-------------------------------------------------------------------------
char RecebeMMC (void)
{
   char b;

   BF = FALSE;
   SSPBUF = 0xff;
   while (! BF);
   b = SSPBUF;

   return b;
}

//-------------------------------------------------------------------------
// 8 pulsos de clock dummy
//-------------------------------------------------------------------------
void MMC8Clock (void)
{
   EnviaMMC (0xff);
   return;
}


//-------------------------------------------------------------------------
// Comando de Reset
//-------------------------------------------------------------------------
void ExecutaCMD0 (void)
{
   char Resp;
   long TimeOut;
   char i;

   // comando CMD0 - Reset
   printf ("\r\n\tResposta ao CMD0...");
   
   do
   {
      SelecionaMMC (FALSE);
     
      Resp = 0xff;
      TimeOut = 100;

      // envia pelo pulsos de clock para inicialização
      for (i = 0; i < 10; i++)   MMC8Clock ();

      // envia CMD0 -> Idle state
      SelecionaMMC (TRUE);
      output_high(PIN_B0);
      EnviaMMC (0x40); // CMD0
      EnviaMMC (0x00);
      EnviaMMC (0x00);
      EnviaMMC (0x00);
      EnviaMMC (0x00);
      EnviaMMC (0x95); // CRC - OK
      MMC8Clock ();

      // espera pela resposta = 0x01 - caso contrário = falha
      while ((Resp != 0x01) && (TimeOut))
      {
         Resp = RecebeMMC ();
         TimeOut--;
      }

      SelecionaMMC (FALSE);
      MMC8Clock ();
   // roda enquanto der timeout
   } while ((! TimeOut) && Resp!=0x00);

   printf ("OK");
   
   return;
}   

//-------------------------------------------------------------------------
// Modo SPI
//-------------------------------------------------------------------------
void ExecutaCMD1 (void)
{
   char Resp;
   long TimeOut;

   // comando CMD1 - Modo SPI
   printf ("\r\n\tResposta ao CMD1...");
   do
   {
      Resp = 0xff;
      TimeOut = 100;


      // envia CMD1 -> Modo SPI
      SelecionaMMC (TRUE);
      EnviaMMC (0x41); // CMD1
      EnviaMMC (0x00);
      EnviaMMC (0x00);
      EnviaMMC (0x00);
      EnviaMMC (0x00);
      EnviaMMC (0x01); // CRC - OK
      MMC8Clock ();

      // espera pela resposta = 0x00 - caso contrário = falha
      while (Resp && TimeOut)
      {
         Resp = RecebeMMC ();
         TimeOut--;
      }

      SelecionaMMC (FALSE);
      MMC8Clock ();

   // roda enquanto der timeout
   } while ((! TimeOut) && Resp!=0x00);

   printf ("OK");
   
   return;
}
   
//-------------------------------------------------------------------------
// Ajusta o tamanho do bloco - 512 bytes
//-------------------------------------------------------------------------
void ExecutaCMD16 (void)
{
   char Resp;
   long TimeOut;
   
   // comando CMD16 - Bloco de 512 bytes
   printf ("\r\n\tResposta ao CMD16...");

   do
   {
      Resp = 0xff;
      TimeOut = 100;

      // envia CMD16 -> block lenght
      SelecionaMMC (TRUE);
      EnviaMMC (0x50); // CMD16
      EnviaMMC (0x00);
      EnviaMMC (0x00);
      EnviaMMC (0x02);
      EnviaMMC (0x00);
      EnviaMMC (0x01); // CRC - OK
      MMC8Clock ();

      // espera pela resposta = 0x00 - caso contrário = falha
      while (Resp && TimeOut)
      {
         Resp = RecebeMMC ();
         TimeOut--;
      }
      SelecionaMMC (FALSE);
      MMC8Clock ();

   // roda enquanto der timeout
   } while ((! TimeOut) && Resp!=0x00);

   printf ("OK");

   return;
}   

//-------------------------------------------------------------------------
// Lê a identificação do cartão - CID
//-------------------------------------------------------------------------
void ExecutaCMD10 (void)
{
   char Resp;
   long TimeOut;
   char i;
   char Ano;
   char Mes;
   char HW;
   char FW;

   // comando CMD10 - Lê a identificação do cartão
   printf ("\r\n\tResposta ao CMD10...");
   
   do
   {
      Resp = 0xff;
      TimeOut = 100;

      SelecionaMMC (TRUE);
         EnviaMMC (0x4A);   //CMD10 - Le CID
         EnviaMMC (0x00);
         EnviaMMC (0x00);
         EnviaMMC (0x00);
         EnviaMMC (0x00);
         EnviaMMC (0x01);
      MMC8Clock ();

      // espera pela resposta = 0x00 - caso contrário = falha
      while (Resp && TimeOut)
      {
         Resp = RecebeMMC ();
         TimeOut--;
      }

      // dummy
      MMC8Clock ();

      // respondeu
      if (TimeOut)
      {

//         // recebe a identificação - binário (8bits)
//         printf ("\r\n\r\n\tID do Fabricante: 0x%x", RecebeMMC ());   // identificação para MMCA
//
//         // recebe a id de aplicação - binário (16bits)
//         printf ("\r\n\tID da Aplicação: 0x");
//         for (i = 0; i < 2; i++)
//         {
//            printf ("%x", RecebeMMC ());   // identificação para MMCA
//         }
//         
//         printf ("\r\n\r\n\tProduto: ");
//         for (i = 0; i < 6; i++)
//         {
//            printf ("%c", RecebeMMC ());   // 6 próximos bytes - Nome do Produto
//         }
//
//         // revisão do produto - 8bits - BCD
//         printf ("\r\n\r\n\tRevisão do Produto: %02d", RecebeMMC ());
//
//         printf ("\r\n\tSerial: 0x");
//         
//         for (i = 0; i < 4; i++)
//         {
//            printf ("%x", RecebeMMC ());   // 4 próximos bytes - Serial do Produto
//         }
//
//         
//
//
//         FW = Resp & 0x0f;               // Firmware = 4bits menos significativos
//         HW = (Resp >> 4) & 0x0f;         // Hardware = 4bits mais significativos
//         printf ("\r\n\tFirmware: %2d", FW);
//         printf ("\r\n\tHardware: %02d", HW);
//         printf ("\r\n\tFW+HW: 0x%x", Resp);
//         
//         
//   
//         Resp = RecebeMMC ();       // Mes + Ano;
//         Ano = Resp & 0x0f;         // Ano = 4bits menos significativos
//         Mes = (Resp >> 4) & 0x0f;   // Ano = 4bits mais significativos
//
//         printf ("\r\n\tAno: %02d", Ano);
//         printf ("\r\n\tMes: %02d", Mes);
//         printf ("\r\n\tAno+Mes: 0x%x\r\n", Resp);
       
      }

      SelecionaMMC (FALSE);
       
   // roda enquanto der timeout
   } while (! TimeOut); 

   printf ("OK"); 
   
   return;
}
   
//-------------------------------------------------------------------------
// Lê o formato do cartão - CSD
//-------------------------------------------------------------------------
void ExecutaCMD9 (void)
{
   char Resp;
   long TimeOut;

   // comando CMD9 - Lê o formato do cartão
   printf ("\r\n\tResposta ao CMD9...");
   
   do
   {
      Resp = 0xff;
      TimeOut = 100;

      SelecionaMMC (TRUE);
         EnviaMMC (0x49);   //CMD9 - Le CSD
         EnviaMMC (0x00);
         EnviaMMC (0x00);
         EnviaMMC (0x00);
         EnviaMMC (0x00);
         EnviaMMC (0x01);
      MMC8Clock ();

      // espera pela resposta = 0x00 - caso contrário = falha
      while (Resp && TimeOut)
      {
         Resp = RecebeMMC ();
         TimeOut--;
      }
       
      // Respondeu
      if (TimeOut)
      {
         
      }

      SelecionaMMC (FALSE);

   // roda enquanto der timeout
   } while (! TimeOut);

   printf ("OK");
   
   return;
}   

//-------------------------------------------------------------------------
// Muda para o modo de high-speed
//-------------------------------------------------------------------------
void ExecutaCMD6 (void)
{
   char Resp;
   long TimeOut;

   // comando CMD6 - high speed (manual mmc plus)
   printf ("\r\n\tResposta ao CMD6...");
   
   do
   {
      Resp = 0xff;
      TimeOut = 100;

      SelecionaMMC (TRUE);
      EnviaMMC (0x46); // CMD6
      EnviaMMC (0x03);
      EnviaMMC (0xb9);
      EnviaMMC (0x01);
      EnviaMMC (0x00);
      EnviaMMC (0x01); // CRC - OK
      MMC8Clock ();

      // espera pela resposta = 0x00 - caso contrário = falha
      while (Resp && TimeOut)
      {
         Resp = RecebeMMC ();
         TimeOut--;
      }
      SelecionaMMC (FALSE);

   // roda enquanto der timeout
   } while (! TimeOut);

   printf ("OK");
   
   return;
}   

//-------------------------------------------------------------------------
// Inicialização do MMC
//-------------------------------------------------------------------------
void InicializaMMC (void)
{

   printf ("\r\nInicializando MMC...");
   
   ExecutaCMD0 ();
   ExecutaCMD1 ();
   ExecutaCMD16 ();
   //ExecutaCMD10 ();
   //ExecutaCMD9 ();
   
   printf ("\r\nInicializando MMC...OK");

   return;
}

//-------------------------------------------------------------------------
// Le um setor da memória - FAT32
//-------------------------------------------------------------------------
void ReadSector(int32 sector, char *buffer)
{
      char errs,response;
      char cnt2,cnt3;

      #byte sectorL = sector
      #byte sectorH = sector+1
      #byte sectorHL = sector+2

      // if (input(CardInserted)) return;
       
   // Disable_interrupts(GLOBAL);
      Restart_wdt();
       
      MMCAddressL = 0;
      MMCAddressH = sectorL;
      MMCAddressHL = sectorH;
      MMCAddressHH = sectorHL;
      gFAT32Vars.MMCAddress <<= 1;

   SelecionaMMC (TRUE);
      EnviaMMC (0x51);
      EnviaMMC (MMCAddressHH);
      EnviaMMC (MMCAddressHL);
      EnviaMMC (MMCAddressH & 0xFE);

      EnviaMMC (0);
      EnviaMMC (0x01);
      errs = 8;
       
   do
   {
       response = RecebeMMC ();
       
     } while ((--errs) && (response == 0xFF));
       
       
      errs = 50;
   
      do
   {
       
         response = RecebeMMC ();
       
      if (response == 0xFE) break;
       
         delay_ms(1);
         
      } while (--errs);
       
      *0xFE9 = (int16) buffer;
   
      cnt3 = 2;
      cnt2 = 0;
   
   do
   {
         do
         {
            SSPBUF = 0xFF;
            while (!BF);
             
            *0xFEE = SSPBUF;
           
      } while (--cnt2);
      } while (--cnt3);
       
       
      response = RecebeMMC ();
      response = RecebeMMC ();
       
   SelecionaMMC (FALSE);
       
//      enable_interrupts(GLOBAL);
}


//-------------------------------------------------------------------------
// Escreve em um setor da memória - FAT32
//-------------------------------------------------------------------------
void WriteSector (int32 sector, char *buffer)
{
   char errs;
      char response;
      char cnt2;
      char cnt3;
      #byte sectorL = sector
      #byte sectorH = sector+1
      #byte sectorHL = sector+2

//      if (input (CardInserted)) return;
   
//      disable_interrupts(GLOBAL);
//      restart_wdt();
   
      MMCAddressL    = 0;
      MMCAddressH    = sectorL;
      MMCAddressHL = sectorH;
      MMCAddressHH = sectorHL;
      gFAT32Vars.MMCAddress <<= 1;
   
      response = 0;

   SelecionaMMC (TRUE);
   
      EnviaMMC (0x58);
       
    EnviaMMC (MMCAddressHH);
    EnviaMMC (MMCAddressHL);
    EnviaMMC (MMCAddressH & 0xFE);
 
      EnviaMMC (0);
      EnviaMMC (0x01);
      MMC8Clock ();
      errs = 8;
       
      do
   {
       response = RecebeMMC ();
       
      } while (--errs && response==0xFF);
       
      if (response)
   {
      SelecionaMMC (FALSE);
       
         MMC8Clock();
//         enable_interrupts(GLOBAL);
         
        return;
      }
       
      MMC8Clock ();
      EnviaMMC (0xFE);
      *0xFE9 = (int16)buffer;
       
      cnt3 = 2;
      cnt2 = 0;
       
   do
   {
       do
       {
            SSPBUF = *0xFEE;
            while (!BF);
            response = SSPBUF;
             
         } while (--cnt2);
         
      } while (--cnt3);
   
      EnviaMMC (0x00);
      EnviaMMC (0x01);
       
      response = RecebeMMC ();
      response ^= 0xE5;
       
      if (response)
   {
       goto endwr3;
      }
       
      do
   {
       response = RecebeMMC ();
       
      } while (response == 0);
       
      response = 0;
       
endwr3:
   SelecionaMMC (FALSE);
    MMC8Clock();
     
//      enable_interrupts (GLOBAL);
}



//-------------------------------------------------------------------------
// mostra um determinado setor - FAT32
//-------------------------------------------------------------------------
void MostraSetor (int32 setor, char *dados, long tamanho)
{
   long i;
   long j;
   long k;

   printf ("\r\n\r\nLendo setor: %lx\r\n\r\n", setor);
   ReadSector (setor, dados);

   j = 0;
   for (i = 0; i < tamanho; i++)
   {
      printf ("%02X ", dados[i]);
      if (j >= 15)
      {
         printf ("          ");

         for (k = (i - 15); k < i; k++)
         {
            if (! isalnum (dados[k])) printf (".");
            else printf ("%c", dados[k]);
         }

         printf ("\r\n");
         j = 0;
      }

      else
      {
         j++;
      }

      delay_ms (1);

   }
}

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Funções da FAT32
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------


char IsSelfDir (char *be)
{
   if (be[0] == '.' && be[1] == '.') return 0xFF;
   else return 0;
}


int16 GetCurrentDOSDate ()
{
   int16 retval;

   retval = myrec.tm_year - 1980;
   retval <<= 9;
   retval |= ((int16)myrec.tm_mon << 5);
   retval |= (int16)myrec.tm_mday;

   return retval;
}

int16 GetCurrentDOSTime ()
{
   int16 retval;

   retval = myrec.tm_hour;
   retval <<= 11;
   retval |= ((int16)myrec.tm_min << 5);
   retval |= (int16)myrec.tm_sec >> 1;
   
   return retval;
}

void InicializaFAT32 (void)
{
    int32 actsector;
    char i;
   
    gFirstEmptyCluster       = 0;
    gFAT32Vars.gStartSector = 0;
       
    // limpa o CREN (comunicação contínua)
    printf ("\r\nInicializando FAT32...");
       
    ReadSector (gFAT32Vars.gStartSector, gFiles[MAXFILES-1].IOpuffer);
       
    if (gFiles[MAXFILES-1].IOpuffer[0] != 0xEB)
    {
        gStartSectorL    = gFiles[MAXFILES-1].IOpuffer[0x1C6];
        gStartSectorH    = gFiles[MAXFILES-1].IOpuffer[0x1C7];
        gStartSectorHL    = gFiles[MAXFILES-1].IOpuffer[0x1C8];
       
        ReadSector (gFAT32Vars.gStartSector, gFiles[MAXFILES-1].IOpuffer);
    }
       
    memcpy (&DiskInfo, gFiles[MAXFILES-1].IOpuffer, sizeof(DiskInfo));
   
    actsector = gFAT32Vars.gStartSector + DiskInfo.Reserved1;
   
    ReadSector (actsector, FATTable);
    gFAT32Vars.FATstartidx = 0;
   
    gFAT32Vars.gFirstDataSector = gFAT32Vars.gStartSector + DiskInfo.FATCopies * DiskInfo.hSectorsPerFat + DiskInfo.Reserved1 - 2;
   
    SecFAT1=DiskInfo.Reserved1;                                                                                 // Nº 1º Sector FAT1
    SecFAT2=DiskInfo.Reserved1+DiskInfo.holdSectorsPerFat;                                                      // Nº 1º Sector FAT2
    FirstRootDirSecNum=(unsigned int16)(DiskInfo.Reserved1+(DiskInfo.FATCopies*DiskInfo.holdSectorsPerFat));    // Nº 1º Sector de Directorio Raiz
    RootDirSecNum=((unsigned int16)(DiskInfo.hMaxRootEntries/DiskInfo.hBytesPerSector)*32);                     // Cant. de sectores utilizados por Directorio Raiz.
   
    BytesPerClus=((unsigned int32)DiskInfo.hBytesPerSector*DiskInfo.bSectorsPerCluster);                        // Nº de Bytes por Cluster.-
   
    for (i = 0; i < MAXFILES; i++)
        gFiles[i].Free = TRUE;
       
   printf ("OK");
   
   return;
}


int32 GetNextCluster (int32 curcluster)
{
      int32 actsector;
      int32 clpage;
      char clpos;

      clpage = curcluster >> 7;
      clpos = curcluster & 0x7F;
       
      if (clpage != gFAT32Vars.FATstartidx)
     {
        // read in the requested page
      actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
         ReadSector (actsector, FATTable);
         
         gFAT32Vars.FATstartidx = clpage;
   }
   
   return (FATTable[clpos]);
}

void SetClusterEntry (int32 curcluster, int32 value)
{
      int32 actsector;
      int32 clpage;
      char clpos;

      clpage = curcluster >> 7;
      clpos = curcluster & 0x7F;
      actsector = gFAT32Vars.gStartSector + DiskInfo.Reserved1 + clpage;
       
      if (clpage != gFAT32Vars.FATstartidx)
   {
       ReadSector (actsector, FATTable);
         gFAT32Vars.FATstartidx = clpage;
      }
   
      FATTable[clpos] = value;
      WriteSector (actsector, FATTable);
      actsector += DiskInfo.hSectorsPerFat;
      WriteSector (actsector,FATTable);
}

void ClearClusterEntry (int32 curcluster)
{
   int32 actsector;
      int32 clpage;
      char clpos;

      clpage = curcluster >> 7;
      clpos = curcluster & 0x7F;
       
      if (clpage != gFAT32Vars.FATstartidx)
   {
       actsector = gFAT32Vars.gStartSector + DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
         WriteSector (actsector, FATTable);
         
         actsector += DiskInfo.hSectorsPerFat;
         WriteSector (actsector,FATTable);
         
         actsector = gFAT32Vars.gStartSector + DiskInfo.Reserved1 + clpage;
         ReadSector (actsector,FATTable);
     
         gFAT32Vars.FATstartidx = clpage;
      }
       
   FATTable[clpos] = 0;
}


int32 FindFirstFreeCluster ()
{
   int32 i;
   int32 st;
   int32 actsector;
   int32 retval;
   char j;

      st = gFirstEmptyCluster;
       
      for (i = st; i < DiskInfo.hSectorsPerFat; i++)
   {
       if (i != gFAT32Vars.FATstartidx)
       {
           actsector = gFAT32Vars.gStartSector + DiskInfo.Reserved1 + i;
           ReadSector (actsector, FATTable);
            gFAT32Vars.FATstartidx = gFirstEmptyCluster = i;
         }
         
         for (j=0;j<128;j++)
         {
            if (FATTable[j] == 0)
           {
               retval = i;
               retval <<= 7;
               retval |= j;
               return retval;
            }
         }
      }
       
      return 0x0FFFFFFF;
}

void ConvertFilename (DIR *beDir, char *name)
{
   char i;
   char j;
   char c;

      j = 0;

      name[0] = 0;

      for (i = 0; i < 8; i++)
   {
       c = beDir->sName[i];
       
         if (c == ' ') break;
         
         name[j++] = c;
      }
     
      for (i = 0; i < 3; i++)
   {
         c = beDir->spam[i];
         
         if ((c == ' ') || (c == 0)) break;
         
         if (!i) name[j++] = '.';
         
       name[j++] = c;
      }
       
      name[j++] = 0;
}

void GetDOSName (DIR *pDir, char *fname)
{
   char i;
   char j;
   char leng;
   char c;
   char toext;

      toext = FALSE;
      j = 0;
       
      leng = strlen(fname);
       
      for (i = 0; i < 8; i++)
       pDir->sName[i] = ' ';
       
      for (i = 0; i < 3; i++)
         pDir->spam[i] = ' ';
         
      for (i = 0; i < leng; i++)
      {
       c = fname[i];
         c = toupper(c);
         
         if (c == '.')
       {
            toext = TRUE;
            continue;
         }
         
         if (toext) pDir->spam[j++] = c;
         else pDir->sName[i] = c;
      }
}


void ReadRootDirectory (char fil)
{
   int32 actsector;

      if (fil > (MAXFILES-1)) return;
       
     actsector = gFAT32Vars.gStartSector + (DiskInfo.FATCopies * DiskInfo.hSectorsPerFat) + DiskInfo.Reserved1;

      ReadSector (actsector, gFiles[fil].IOpuffer);
       
   gFAT32Vars.gDirEntrySector = actsector;
      gFiles[fil].dirSector = actsector;
      gFiles[fil].dirIdx = 0;
      memcpy (&(gFiles[fil].DirEntry), gFiles[fil].IOpuffer,32);
      gFiles[fil].CurrentCluster = DiskInfo.hRootStartCluster;
}


char FindDirEntry (char *fname, char f)
{
    DIR *pDir;
    int16 i;
    char filename[16];
    int32 nextcluster;
    int32 actsector;
   
    if (f > (MAXFILES-1)) return FALSE;
   
    gFAT32Vars.gFirstEmptyDirEntry = 0xFFFF;
    gFAT32Vars.gFirstDirEntryCluster = 0x0FFFFFFF;
       
   do
   {
       pDir = (DIR*)(gFiles[f].IOpuffer);
       
         for (i = 0; i < 16; i++)
       {
            if (((pDir->sName[0] == 0xE5) || (pDir->sName[0] == 0)) && (gFAT32Vars.gFirstEmptyDirEntry == 0xFFFF))
           {
              // store first free
                 gFAT32Vars.gFirstEmptyDirEntry = i;
               gFAT32Vars.gFirstDirEntryCluster = gFiles[f].CurrentCluster;
            }

               if (pDir->sName[0] == 0) return FALSE;
                 
         ConvertFilename (pDir,filename);
             if (!strcmp (filename, fname))
           {
               memcpy(&(gFiles[f].DirEntry), pDir, 32);
               gFiles[f].dirIdx = i;
               gFAT32Vars.gDirEntryIdx = i;
               return TRUE;
            }
             
            pDir++;
         }
         
         nextcluster = GetNextCluster (gFiles[f].CurrentCluster);
         
         
            if ((nextcluster != 0x0FFFFFFF) && (nextcluster != 0))
       {
            actsector = nextcluster + gFAT32Vars.gFirstDataSector;
            ReadSector (actsector, gFiles[f].IOpuffer);
             
            gFAT32Vars.gDirEntrySector = actsector;
            gFiles[f].dirSector = actsector;
            gFiles[f].CurrentCluster = nextcluster;
         }
       
         
      } while ((nextcluster != 0x0FFFFFFF) && (nextcluster != 0));
       
      return FALSE;
}

// file I/O routines
char *TryFile(char *fname, char *f)
{
   char i;
      char leng;
      char *filename;

      (*f) = 0xFF;
   
      for (i = 0; i < MAXFILES; i++)
   {
         if (gFiles[i].Free)
        {
           (*f) = i;
            break;
         }
      }
       
      if ((*f) == 0xFF) return 0;
       
      ReadRootDirectory (*f);
       
      filename = fname;
      leng = strlen (fname);
       
      for (i = 0; i < leng; i++)
   {
       if (fname[i] == '/')
       {
           fname[i] = 0;
             
            if (! cwd (filename,(*f)))
           {
                 gFiles[(*f)].Free = TRUE;
               return 0;
            }
         
            filename = fname + i + 1;
             
        }
      }
   
      return filename;
}

char fcreate (char f, char *fname)
{
   DIR *pDir;
      int32 actsector;
      char actcl;
      int16 i;

      if (f > (MAXFILES-1)) return FALSE;
       
      if (gFAT32Vars.gFirstDirEntryCluster == 0x0FFFFFFF)
   {
       // extend the directory file !!!
         gFAT32Vars.gFirstDirEntryCluster = FindFirstFreeCluster ();
         gFAT32Vars.gFirstEmptyDirEntry = 0;
         SetClusterEntry(gFiles[f].CurrentCluster, gFAT32Vars.gFirstDirEntryCluster);
      SetClusterEntry(gFAT32Vars.gFirstDirEntryCluster, 0x0FFFFFFF);
         actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector;
         
         for (i = 0; i < 512; i++)
         {
            gFiles[f].IOpuffer[i] = 0;
        }
       
         WriteSector(actsector, gFiles[f].IOpuffer);
      }
       
      actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector;
      ReadSector (actsector, gFiles[f].IOpuffer);
   
   
      pDir = (DIR*)(&(gFiles[f].IOpuffer[32 * gFAT32Vars.gFirstEmptyDirEntry]));
      gFiles[f].dirSector = actsector;
      gFiles[f].dirIdx = gFAT32Vars.gFirstEmptyDirEntry;
       
      GetDOSName (pDir, fname);
       
      pDir->bAttr = 0;
      actcl = FindFirstFreeCluster ();
      pDir->hCluster = actcl & 0xFFFF;
      pDir->hClusterH = actcl >> 16;
       
      SetClusterEntry (actcl, 0x0FFFFFFF);
      pDir->wSize = 0;
      gFiles[f].position = 0;
      pDir->hDate = GetCurrentDOSDate ();
      pDir->hTime = GetCurrentDOSTime ();
       
      WriteSector (actsector, gFiles[f].IOpuffer);
      memcpy (&(gFiles[f].DirEntry), pDir,32);
       
   return TRUE;
}

int32 ComposeCluster (char f)
{
   int32 retval;

   retval = gFiles[f].DirEntry.hClusterH;
   retval <<= 16;
   retval |= gFiles[f].DirEntry.hCluster;

   return retval;
}

char fopen (char *fname, char mode)
{
   char found;
      char f;
      int32 actsector;
      int32 actcluster;
      int32 nextcluster;
      char *filename;

      //if (input(CardInserted)) return 0xFF;
   
             
      filename = TryFile (fname, &f);

      if (filename == 0) return 0xFF;

      found = FALSE;
      found = FindDirEntry (filename,f);

       
      if (!found)
   {
         if (mode == 'r')
         {
            gFiles[f].Free = TRUE;
            return 0xFF;
         }
       else
      {
           if (! fcreate(f, filename)) return 0xFF;
            found = TRUE;
         }
      }
   
   if (found)
   {
         gFiles[f].Free = FALSE;
         gFiles[f].mode = mode;
         
         if  (mode == 'a') // com problemas
       {
           gFiles[f].position = gFiles[f].DirEntry.wSize;
           
            actcluster = ComposeCluster(f);
             
            while ((actcluster != 0x0FFFFFFF) && (nextcluster != 0))
           {
               nextcluster = GetNextCluster(actcluster);
                   
                  if ((nextcluster == 0x0FFFFFFF) || (nextcluster == 0)) break;
                   
                  actcluster = nextcluster;
            }
           
            actsector = actcluster + gFAT32Vars.gFirstDataSector;
            ReadSector (actsector, gFiles[f].IOpuffer);
             
            gFiles[f].CurrentCluster = actcluster;
            gFiles[f].posinsector = gFiles[f].position & 0x01FF;
             
            if ((gFiles[f].posinsector == 0) && (gFiles[f].position != 0))
            {
               gFiles[f].posinsector = 512;
         }   
         }
       
      else
      {
           gFiles[f].position = 0;
           
            actsector = ComposeCluster (f);
            actsector += gFAT32Vars.gFirstDataSector;
         ReadSector(actsector,gFiles[f].IOpuffer);
         
            gFiles[f].CurrentCluster = ComposeCluster (f);
            gFiles[f].posinsector = 0;
         }
      }
   
      return f;
}

void fclose (char f)
{
      if (f > (MAXFILES-1)) return;
      if ((gFiles[f].mode == 'a') || (gFiles[f].mode == 'w')) fflush(f);
       
      gFiles[f].Free = TRUE;
}

void fflush (char f)
{
   int32 actsector;
   DIR *pDir;

      if (f > (MAXFILES-1)) return;
   
      actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
      WriteSector (actsector, gFiles[f].IOpuffer);
      ReadSector(gFiles[f].dirSector, gFiles[f].IOpuffer);
   
      pDir = (DIR*)(&(gFiles[f].IOpuffer[32 * gFiles[f].dirIdx]));
   
      if (gFiles[f].DirEntry.bAttr & 0x10) pDir->wSize = 0; // if it is a directory
      else pDir->wSize = gFiles[f].position;
   
      pDir->hDate = GetCurrentDOSDate ();
      pDir->hTime = GetCurrentDOSTime ();
      WriteSector(gFiles[f].dirSector,gFiles[f].IOpuffer);
      ReadSector(actsector, gFiles[f].IOpuffer);
}

char cwd (char *fname, char f)
{
   int32 actsector;

     if (f > (MAXFILES-1))
      {
      return FALSE; // just in case of overaddressing
      }
   
   if (IsSelfDir(fname))
      {
         return TRUE; // already in Root dir
      }   
       
      if (!FindDirEntry(fname,f))
      {
         return FALSE; // not found
      }

 
      actsector = ComposeCluster (f);
      actsector += gFAT32Vars.gFirstDataSector; // read current dir
      ReadSector (actsector, gFiles[f].IOpuffer);
       
      gFAT32Vars.gDirEntrySector = actsector;
      gFiles[f].dirSector = actsector;
      gFiles[f].CurrentCluster = ComposeCluster (f);
             
      return TRUE;
}

void fputch (char be, char f)
{
      int32 nextcluster;
      int32 actsector;

      if (f > (MAXFILES-1)) return;
       
      if (gFiles[f].posinsector == 512)
   {
       actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
         WriteSector (actsector,gFiles[f].IOpuffer);
         
         nextcluster = FindFirstFreeCluster ();
     
       if ((nextcluster != 0x0FFFFFFF) && (nextcluster != 0))
      {
           SetClusterEntry (gFiles[f].CurrentCluster, nextcluster);
            SetClusterEntry (nextcluster, 0x0FFFFFFF);
            actsector = nextcluster + gFAT32Vars.gFirstDataSector;
            //ReadSector (actsector,gFiles[f].IOpuffer);  //-- nao tem a necessidade de ler o setor toda vez que for gravar um bloco
            gFiles[f].CurrentCluster = nextcluster;
            gFiles[f].posinsector = 0;
         }
      }
       
      gFiles[f].IOpuffer[gFiles[f].posinsector] = be;
      gFiles[f].posinsector++;
      gFiles[f].position++;

   return;       
}

void fputstring (char *be, char f)
{
   int16 leng;
   int16 i;

      if (f > (MAXFILES-1)) return;
   
      leng = strlen (be);
   
      for (i = 0; i < leng; i++)
       fputch (be[i], f);
   
}

int16 fread (char *buffer, int16 leng, char f)
{
   int16 i;
   int16 retv;
   char c;
   char v;

      if (f > (MAXFILES-1)) return 0;
       
      retv = 0;
       
      for (i = 0; i < leng; i++)
   {
       v = fgetch (&c, f);
       
         if (v)
        {
           buffer[i] = c;
            retv++;
         }
         
         else break;
      }
   
      return retv;
}

void fwrite (char *buffer, int16 leng, char f)
{
   int16 i;

      if (f > (MAXFILES-1)) return;
       
      for (i = 0; i < leng; i++)
       fputch (buffer[i],f);

}


char fgetch (char *ki, char f)
{
      int32 nextcluster;
      int32 actsector;

      if (f > (MAXFILES-1)) return FALSE;
       
      if (gFiles[f].position >= gFiles[f].DirEntry.wSize) return FALSE;
       
      *ki = gFiles[f].IOpuffer[gFiles[f].posinsector];
       
      gFiles[f].posinsector++;
      gFiles[f].position++;
   
   if (gFiles[f].posinsector == 512)
   {
       nextcluster = GetNextCluster (gFiles[f].CurrentCluster);
       
         if ((nextcluster != 0x0FFFFFFF) && (nextcluster != 0))
         {
            actsector = nextcluster + gFAT32Vars.gFirstDataSector;
            ReadSector (actsector,gFiles[f].IOpuffer);
             
            gFiles[f].CurrentCluster = nextcluster;
            gFiles[f].posinsector = 0;
         }
      }
   
      return TRUE;
}

char remove (char *fname)
{
      char i;
      char found;
      char f;
      DIR *pDir;
      int32 nextcluster;
      int32 currentcluster;
      char *filename;

      filename = TryFile (fname, &f);
       
      if (filename == 0) return FALSE;
       
      found = FindDirEntry (filename,f);
       
   if (!found)
   {
       gFiles[f].Free = TRUE;
       
       printf ("Arquivo não encontrado...\r\n");
         return FALSE;
      }
       
   
   
      pDir = (DIR*)(&(gFiles[f].IOpuffer[32 * gFAT32Vars.gDirEntryIdx]));
      pDir->sName[0] = 0xE5;
       
      for (i = 1; i < 8; i++)
      pDir->sName[i] = ' ';
       
      for (i = 0; i < 3; i++)
         pDir->spam[i] = ' ';
         
      WriteSector (gFAT32Vars.gDirEntrySector, gFiles[f].IOpuffer);
      currentcluster = ComposeCluster (f);
       
      while ((currentcluster != 0x0FFFFFFF) && (nextcluster != 0))
   {
       nextcluster = GetNextCluster (currentcluster);
         ClearClusterEntry (currentcluster);
          currentcluster = nextcluster;
      }
       
      ClearClusterEntry (currentcluster);
      SetClusterEntry (currentcluster, 0);
      currentcluster = gFAT32Vars.gStartSector + DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
      WriteSector (currentcluster, FATTable);
      currentcluster += DiskInfo.hSectorsPerFat;
      WriteSector (currentcluster, FATTable);
      gFiles[f].Free = TRUE;
   
      return TRUE;
}

char getfsize (char *fname, int32 *fsiz)
{
      char found;
      char f;
      DIR *pDir;
      char *filename;

      filename = TryFile (fname, &f);
       
      if (filename == 0) return FALSE;
       
      found = FindDirEntry (filename, f);
   
   if (!found)
   {
       gFiles[f].Free = TRUE;
       
         return FALSE;
      }
   
      pDir = (DIR*)(&(gFiles[f].IOpuffer[32 * gFAT32Vars.gDirEntryIdx]));
   
      gFiles[f].Free = TRUE;
      *fsiz = pDir->wSize;
   
      return TRUE;
}




Alentado por este éxito y leyendo un poco más fino en el foro, encuentro la versión en la que la librería tuya, Suky, posee la inicialización tanto para MMC/SD como las SDHC (que son las que se consiguen hoy). Entonces decidí hacer una pequeña prueba y logré iniciar todas las memorias. O por lo menos eso parece que dice el debug, ya que al leer el sector 0x00000000, nuevamente tengo todo cero. Lo bueno es que ahora es con todas las memorias, tanto MMC/SD como SDHC   :mrgreen:

Comparando esta librería con la del brasilero, estoy tratando de lograr una final que ande perfecto con cualquier memoria. Así luego poder seguir con la librería FAT que ya nos compartió en oportunidades anteriores!

Espe

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #220 en: 09 de Octubre de 2013, 15:56:10 »
Suky, ahi realicé lo que me decías de escribir y leer. El código es:

for(ptr_buff=0; ptr_buff<512; ptr_buff+=2)
{
    BufferFAT[ptr_buff] = 0xFF;
    BufferFAT[ptr_buff+1] = 0x00;
}
                       
SDCard_write_block(0x200,&BufferFAT[0]);
                       
for(ptr_buff=0; ptr_buff<512; ptr_buff++)
    BufferFAT[ptr_buff] = 0x55;
                           
SDCard_read_block(0x200,&BufferFAT[0]);

Al medio, entre escritura y lectura, cargo el BufferFAT con cualquier cosa, para saber si lo que leo es realmente lo que escribí. Lee y escribe, pero solo si lo hago desde el PIC. Es decir, cuando agarro el WinHex, no encuentro por ningún lado lo que escribí  :shock:. Como puede ser??????

Saludos!

Desconectado RICHI777

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1498
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #221 en: 09 de Octubre de 2013, 16:36:34 »
Hola,

Citar
Suky, no se cómo me serviría esa prueba ya que, para iniciar el FAT, es necesario leer el primer sector de la SD. Si yo trato de escribir y luego leer lo que escribí, no gano nada. Seguiría sin poder leer la 0x00000000.

Lo que quiso comentar Suky, es que antes de probar el sistema de archivo es necesario tener la certeza de que la comunicación con la SD/MMC funcione perfecto. Una vez que funcione eso, lo del sistema de archivos es casi trivial. Como a la tarjeta la accedes por LBA escribiendo ejemplo 0x55 y leyendo lo mismo en sector, muchisimas veces, te aseguras de que el bajo nivel funcione.

Yo al igual que Suky, publique un código similar, digamos que el trabajo de Suky era mucho mas completo que el mio. Algunas personas usaron mi código, hace un par de años me contacte personalmente con una persona que me comentaba que para ciertos modelos la SD nunca se inicializaba, y me mando varias muestras. No hubo caso no había manera de hacerlas funcionar, si tocaba algo en el código, otras memorias que antes funcionaban dejaban de hacerlo. Investigando un poco descubrí que muchas de las memorias que se consiguen aquí ( Argentina ) son memorias truchas chinas que no cumplen con los estándares, así que a esta persona le di un besito en la frente y no hice nada.

Problema complicado ...

Saludos !


« Última modificación: 09 de Octubre de 2013, 16:42:58 por RICHI777 »

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #222 en: 10 de Octubre de 2013, 12:36:08 »
Buenas a todos!!!!

Hoy he logrado un enorme avance. Tal cual y como les había dicho antes, ya había comenzado a poder terminar de iniciar la memorias, basado en la versión aquí publicada de Suky, luego de varios retoques y pruebas.

A pesar del mucho renegar, probar, medir con el osciloscopio y leer, leer y más leer, logré retocar la librería de Suky para que funcione correctamente con el compilador CCS, versión 4.114. No solo iniciando la memoria, si no que también, leyendo el boot sector donde se encuentra la FAT. A su vez, logré terminar de integrar en una sola librería el correcto funcionamiento para MMC, SD y SDHC...  :-/ :-/ :-/

Todo este trabajo fue realizando una integración entre la librería de Suky y la librería del brasilero ANDRE L. V. SILVA, todo esto junto a toda la experiencia que pude realizar y a los conocimientos leyendo todo lo que se conseguía respecto a SD y FAT. SAí mismo, todavía queda empezar con las pruebas de creación de carpetas y archivos, junto a las demás funciones del FAT. Pero lo importante y más complejo, leer el boot sector, leer y escribir cualquier sector, y poder manejar tanto MMS/SD y SDHC.  8)

En las librería que subo, están las que funcionan correctamente, más la que no han sido tocadas. Las que he estado trabajando y modificando, he tratado de de dejar nota de las modificaciones y, dentro de lo que se podía, el por que o para qué. Así mismo, las librerías modificadas, tiene la cabecera modificada, con el agregado de los detalles de lo realizado por mi.

Espero que puedan usarlas y probarlas con otros compiladores y micros, para ver si completamente quedó una librería global y completa, dentro de lo posible.

Saludos!!!

Desconectado gajobar

  • PIC10
  • *
  • Mensajes: 13
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #223 en: 22 de Octubre de 2013, 17:06:13 »
Buenas a Todos!!!!!  :-/ :-/

Bueno, ya estando todo OK y funcionando, subo el aporte final.

Funciona para SD/MMC y para SDHC. He probado diversas marcas y todas andan bien. Las marcas probadas son Kignston, Sandisk y Nokia, hasta 4GB. Funciona para crear y buscar directorios, para crear y buscar archivos. He probado diferentes tamaños y extensiones y va todo OK.   :-/ :-/

Espero que no tengan ninguna complicación, pero en la vida real funciona perfectamente, además del simulador.  ((:-)) ((:-)) Eso si, no dejen de agradecer y de usar a cabecera, que salen los aportes y originales de los participantes.

Saludos

Desconectado Suky

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Comenzando con memorias SD/MMC. Librería a nivel hardware.
« Respuesta #224 en: 22 de Octubre de 2013, 20:29:23 »
Felicitaciones por el trabajo!  ((:-))
No contesto mensajes privados, las consultas en el foro


 

anything