while(i < TamanhoBloco)
{
//Começa a transferir dados para o buffer
status=rSDIFSTA;
if((status&0x2000)==0x2000)
{ //Se o FIFO de envio estiver disponível, ou seja, não estiver cheio
rSDIDAT = *BufferTx;
BufferTx++;
i++;
}
}
**Depuração e Análise do Problema:**Durante a depuração, descobriu-se que quando a escrita falha, a detecção de FIFO disponível para transmissão (TFDET) é 0, o que significa que o FIFO está cheio. Nesse momento, o programa entra em loop 16 vezes (i=0x10). Cada ciclo escreve 4 bytes, e 16 ciclos preenchem exatamente a capacidade máxima do FIFO de 64 bytes. Isso prova que os dados escritos no FIFO, que deveriam ser enviados para o cartão SD e esvaziar o FIFO para permitir que o usuário continue escrevendo, ficam retidos no FIFO, com entrada mas sem saída. É como se a estação de transição de um esgoto estivesse entupida, impedindo que o esgoto a montante continue despejando. A operação de escrita seguida de leitura funciona normalmente. Imprimi os valores de alguns registradores após a execução da função de escrita, conforme mostrado na figura esquerda. Pode-se observar que após a escrita, os registradores rSDIDCNT e rSDIDSTA retornam aos seus valores iniciais. A figura direita mostra os valores dos registradores após a execução da função de leitura. Nota-se que após a execução da função de leitura, os registradores rSDIDCNT e rSDIDSTA não retornam aos valores iniciais, permanecendo no estado da execução da função de leitura. Em outras palavras, a função de leitura não foi executada completamente, e o módulo SDMMC não entrou no estado ocioso. Sem estar pronto, a continuação da operação de escrita não pode ter sucesso. **Solução**A solução principal é garantir que, seja qual for a operação (leitura ou escrita), o barramento SDIO esteja ocioso antes de sair da função atual. Isso garante que em operações subsequentes, o módulo SDMMC esteja pronto e não em um estado residual. **Função de Leitura**
/********************************************************************************** Função: Esta função é usada para ler um único bloco de dados a partir do cartão SD, a partir de um endereço específico Parâmetros: U32 Endereco - Endereço inicial do bloco a ser lido U8* BufferRx - Buffer para receber os dados lidos Valor de retorno: 0 - Falha na operação de leitura do bloco 1 - Sucesso na operação de leitura do bloco Exemplo: Na função principal, defina um array como buffer de recebimento, como U8 Buffer_receber[TamanhoBloco]; Em seguida, chame Ler_Bloco_Unico(endereco, Buffer_receber); **********************************************************************************/ U8 Ler_Bloco_Unico(U32 Endereco,U8 * BufferRx) { U16 i=0; U32 status=0; U16 TamanhoBloco; //Define o tamanho do bloco U16 NumeroBloco;
TamanhoBloco=1 << TamanhoBlocoSD; //Em bytes
NumeroBloco = ((Endereco >> TamanhoBlocoSD) + 1) &0x0fff;
rSDIDTIMER=0x7fffff; //Define a contagem de tempo limite
rSDIBSIZE=0x200; //512 bytes (128 palavras)
rSDIFSTA=rSDIFSTA|(1<<16); //Reset do FIFO
rSDIDCON = (NumeroBloco<<0)|(2<<12)|(1<<14)|(1<<16)|(1<<17)|(1<<19)|(0<<22);
while(CMD17(Endereco)!=1) //Envia o comando de leitura de bloco único
{
#ifdef SD_MMC_DEBUG Uart_Printf("Falha ao enviar endereço de leitura!\n"); #endif }
/* Começa a receber dados no buffer */
while(i<tamanhobloco :="" __sd_mmc_debug__="" a="" ao="" atraso="" barramento="" bufferrx="" cart="" crc="" dados="" de="" do="" e="" entrou="" erro="" estado="" fifo="" flags="" houve="" houver="" i="" if="" ler:="" limite="" m="" no="" o="" ocioso="" os="" ou="" recebimento="" recep="" return="" rsdidcon="rSDIDCON&~(7<<12);" rsdidsta="(0x3<<0x5);" rsdidtimer="0x7fffff;" sd="" sdio="" sdmmc="" se="" status="rSDIDSTA;" tempo="" uart_printf="" verifica="" while="">
Função de Escrita
/**********************************************************************************
Função: Esta função é usada para escrever dados em um bloco de dados do cartão SD
Parâmetros:
U32 Endereco - Endereço inicial do bloco a ser escrito
U8* BufferTx - Buffer para enviar os dados
Valor de retorno:
0 - Falha na operação de escrita de dados
1 - Sucesso na operação de escrita de dados
Exemplo:
Na função principal, defina um array como buffer de envio, como U8 Buffer_enviar[TamanhoBloco];
Em seguida, chame Escrever_Bloco_Unico(endereco, Buffer_enviar);
**********************************************************************************/
U8 Escrever_Bloco_Unico(U32 Endereco,const U8 * BufferTx)
{
U16 i = 0;
U32 status = 0;
U16 TamanhoBloco; //Define o tamanho do bloco
U16 NumeroBloco;
TamanhoBloco = 1<< TamanhoBlocoSD; //Em bytes
NumeroBloco = ((Endereco >> TamanhoBlocoSD) +1) &0x0fff;
rSDIDTIMER=0x7fffff; //Define a contagem de tempo limite
rSDIBSIZE=0x200; //512 bytes (128 palavras)
rSDIFSTA = rSDIFSTA|(1<<16); //Reset do FIFO
rSDIDCON = NumeroBloco|(3<<12)|(1<<14)|(1<<16)|(1<<17)|(1<<20)|(0<<22);
while(CMD24(Endereco)!=1) //Envia o comando de escrita de bloco único
{
#ifdef __SD_MMC_DEBUG__
Uart_Printf("Falha ao enviar endereço de escrita!\n");
#endif
}
/* Começa a transferir dados para o buffer */
while(i < TamanhoBloco)
{
status=rSDIFSTA;
if((status&0x2000)==0x2000) //Se o FIFO de envio estiver disponível, ou seja, não estiver cheio
{
rSDIDAT = *BufferTx;
BufferTx++;
i++;
}
}
status = rSDIDSTA;
Atraso(5);
rSDIDCON=rSDIDCON&~(7<<12); //Finaliza o envio do módulo SDMMC
rSDIDSTA = status;
/* Verifica se o cartão SD entrou no estado ocioso - barramento SDIO ocioso */
rSDIDCON=(0<<18)|(1<<17)|(1<<16)|(1<<14)|(1<<12)|(NumeroBloco<<0);
rSDIDTIMER=0x7fffff; //Define a contagem de tempo limite
status = rSDIDSTA;
while( !( ((status&0x08)==0x08) | ((status&0x20)==0x20)| ((status&0x800)==0x800) )){
status=rSDIDSTA;
}
if( (status&0x20) == 0x20 ){
rSDIDSTA = status;
return 0;
}
rSDIDSTA = status;
return 1;
}
Resultados dos TestesAs seguintes operações foram validadas com sucesso: - Leitura de bloco único - Escrita de bloco único - Leitura de múltiplos blocos (implementada chamando a função de leitura de bloco único) - Escrita de múltiplos blocos (implementada chamando a função de escrita de bloco único) - Leitura seguida de escrita - Escrita seguida de leitura Teste com sistema de arquivos FATFS移植: A maioria das operações não apresentou falhas, mas ocasionalemnte também ocorreu a situação da função de escrita travar. Bugs Ainda Existentes1. A função de leitura, ao verificar se o barramento SDIO está ocioso, frequentemente entra em estado de tempo limite, o que torna a função de leitura muito lenta. 2. Ao testar com o sistema de arquivso FATFS移植, ocasionalmente também ocorre a situação da função de escrita travar. Devido ao driver de baixo nível operar lentamente, o sistema de arquivos fica muito lento. Salvar um arquivo bmp de 482KB leva mais de dez segundos.