Problema de Escrita em Cartão SD Após Leitura em Programas Nativos para TQ2440

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.

Tags: SD card TQ2440 Sistemas Embarcados SDIO FIFO

Publicado em 7-2 01:58