Aplicação do sistema de arquivos FatFS no MCU

Siga a conta pública + estrela e nunca perca conteúdos interessantes

4639aa757e361d6c2ee7851c1eeeffb2.gif

Reimpresso de | Munan Chuangzhi

O sistema de arquivos FatFS é um sistema de arquivos bem conhecido na área de microcontroladores. Devido à sua leveza e compatibilidade, é preferido pelos desenvolvedores de MCU.

Ao implementar tarefas como ler e gravar arquivos em discos U e cartões SD, muitas vezes precisamos de um sistema de arquivos para apoiar nosso trabalho. Especialmente em algumas aplicações MCU, a adição de um sistema de arquivos pode melhorar significativamente a facilidade de interação do sistema.

Neste artigo, discutiremos o transplante e aplicação do sistema de arquivos FatFS no STM32F4.

1. Preparação

Precisamos fazer alguns preparativos necessários antes de iniciar o transplante de FatFS. Primeiro, você precisa preparar a plataforma de hardware correspondente. Estamos usando a plataforma operacional STM32F407VET6 aqui. O trabalho de portabilidade de bibliotecas relacionadas a hardware USB também foi concluído.

Em segundo lugar, também precisamos preparar o código-fonte relevante do FatFS, aqui usamos a versão mais recente R0.14b, que pode ser baixada do site:

http://elm-chan.org/fsw/ff/00index_e.html

Após a descompactação do código-fonte baixado, existem duas pastas: documento e fonte. A pasta de documentos contém a documentação relevante, que é igual ao conteúdo do site. Você pode visualizar esses documentos para funcionar durante o transplante. A pasta Fonte contém arquivos relacionados ao código-fonte, incluindo principalmente:

0967e81e2771d36912f092d380382c08.png

Dentre as séries de arquivos mostradas na imagem acima, o arquivo 00readme.txt possui uma introdução para cada arquivo, visualizamos seu conteúdo da seguinte forma:

00readme.txt arquivo leia-me
00history.txt Arquivo de registro de versão
ff.c Módulo FatFs
ffconf.h Arquivo de configuração do módulo FatFs
aff.h Arquivo de cabeçalho do módulo de aplicação FatFs
disco.h Arquivos de cabeçalho para FatFs e módulos IO de disco
disco.c Um exemplo de anexação de funções de E/S de disco ao FatFS
funicode.c Função de codificação Unicode
ffsystem.c Exemplos de arquivos opcionais relacionados ao sistema operacional

Entre esses arquivos, ff.c e ff.h são arquivos principais. ffunicode.c é a codificação de caracteres, e a codificação será selecionada de acordo com a configuração do arquivo de configuração. O arquivo ffsystem.c é determinado de acordo com suas necessidades. Portanto, os arquivos que estão relacionados à plataforma específica da aplicação e precisam ser implementados por nós são o arquivo de configuração ffconf.h e os arquivos de operação de disco diskio.h e diskio.c. Esses arquivos também são o foco de nosso transplante.

2. Implementar transplante

  Concluímos o trabalho de preparação para o transplante e agora implementaremos o transplante de aplicativos para discos USB de grande capacidade. Como dissemos antes, os arquivos que precisam ser processados ​​para transplante são o arquivo de configuração ffconf.h e os arquivos de operação de disco diskio.h e diskio.c.

  Em relação ao arquivo de configuração ffconf.h, ele na verdade possui uma instância dele mesmo, só precisamos modificar a configuração conforme necessário. Os parâmetros de configuração que precisamos modificar aqui incluem:

  O parâmetro de configuração do método de codificação suportado FF_CODE_PAGE está relacionado ao problema de codificação de arquivo. Nós o configuramos para suportar chinês simplificado.

  A quantidade de drives lógicos configura o parâmetro FF_VOLUMES.O FatFS pode ser aplicado a vários drives ao mesmo tempo, portanto precisamos configurar o número de drives de acordo com a situação real.

  Parâmetro de configuração de timestamp FF_FS_NORTC, na maioria das vezes não precisamos registrar timestamps, então o desligamos aqui.

  O resto são funções relacionadas para implementar operações de IO de disco. O documento de ajuda do FatFS nos diz que existem dois tipos de funções que precisam ser implementadas: uma é a função relacionada ao controle do dispositivo de disco, principalmente funções para obter o status do dispositivo, inicializar funções do dispositivo, e leitura. Funções de dados, funções de gravação de dados e funções de função relacionadas ao dispositivo de controle; a segunda categoria é a função de operação do relógio em tempo real, que é usada principalmente para obter a função de tempo atual. Portanto, implementar essas 6 funções é a principal tarefa do transplante.

2.1. Obter função de status do dispositivo

  Função de detecção de status do disco disk_status. Usado para detectar o status do disco e será chamado no arquivo ff.c. Seu protótipo de função é o seguinte:

  DSTATUS disk_status(BYTE drV);

  De acordo com a definição do protótipo e os requisitos do nosso dispositivo de armazenamento em massa USB, podemos implementar a função de aquisição do status do disco da seguinte forma:

/*用于USBH的状态获取函数*/
static DSTATUS USBH_status(BYTE lun)
{
 DRESULT res = RES_ERROR;

 if(USBH_MSC_UnitIsReady(&hUsbHostFS, lun))
 {
  res = RES_OK;
 }
 else
 {
  res = RES_ERROR;
 }

 return res;
}

2.2. Inicializar função do dispositivo

  Função de inicialização da mídia de armazenamento disk_initialize. É usado para inicializar o dispositivo de disco e será chamado no arquivo ff.c. Seu protótipo de função é o seguinte:

  DSTATUS disk_initialize(BYTE drv);

  De acordo com a definição do protótipo e os requisitos do nosso dispositivo de armazenamento em massa USB, podemos implementar a função de inicialização da unidade de disco, mas na verdade não precisamos dela aqui, porque a inicialização foi concluída na biblioteca USB HOST, então basta retornar o função correta diretamente.

/*用于USBH的初始化函数*/
static DSTATUS USBH_initialize(BYTE lun)
{
  //USB HOST库中已经完成了初始化
 return RES_OK;
}

2.3. Ler dados

  Leia a função do setor disk_read. É usado para ler dados do disco, é escrito de acordo com o IO específico do disco e será chamado no arquivo ff.c. Seu protótipo de função é o seguinte:

  DRESULT disk_read (BYTE drv, BYTE * buff, setor DWORD, BYTE. contagem);

  De acordo com a definição do protótipo e os requisitos do nosso dispositivo de armazenamento em massa USB, podemos implementar a função de leitura de dados do disco da seguinte forma:

/*用于USBH的读扇区函数*/
static DRESULT USBH_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
 DRESULT res = RES_ERROR;
 MSC_LUNTypeDef info;

 if(USBH_MSC_Read(&hUsbHostFS, lun, sector, buff, count) == USBH_OK)
 {
  res = RES_OK;
 }
 else
 {
  USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info);

  switch (info.sense.asc)
  {
  case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
  case SCSI_ASC_MEDIUM_NOT_PRESENT:
  case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
   USBH_ErrLog ("USB Disk is not ready!");
   res = RES_NOTRDY;
   break;

  default:
   res = RES_ERROR;
   break;
  }
 }

 return res;
}

2.4. Gravar dados

  Escreva a função do setor disk_write. É usado para gravar dados do disco, é gravado de acordo com o IO específico do disco e será chamado no arquivo ff.c. Seu protótipo de função é o seguinte:

  DRESULT disk_write (BYTE drv, const BYTE * buff, setor DWORD, contagem de BYTE);

  De acordo com a definição do protótipo e os requisitos do nosso dispositivo de armazenamento em massa USB, podemos implementar a função de gravação de dados em disco da seguinte forma:

/*用于USBH的写扇区函数*/
static DRESULT USBH_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
 DRESULT res = RES_ERROR;
 MSC_LUNTypeDef info;

 if(USBH_MSC_Write(&hUsbHostFS, lun, sector, (BYTE *)buff, count) == USBH_OK)
 {
  res = RES_OK;
 }
 else
 {
  USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info);

  switch (info.sense.asc)
  {
  case SCSI_ASC_WRITE_PROTECTED:
   USBH_ErrLog("USB Disk is Write protected!");
   res = RES_WRPRT;
   break;

  case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
  case SCSI_ASC_MEDIUM_NOT_PRESENT:
  case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
   USBH_ErrLog("USB Disk is not ready!");
   res = RES_NOTRDY;
   break;

  default:
   res = RES_ERROR;
   break;
  }
 }

 return res;
}

2.5. Funções relacionadas ao dispositivo de controle

  Função de controle de mídia de armazenamento disk_ioctl. Você pode escrever o código funcional necessário nesta função, como obter o tamanho da mídia de armazenamento, detectar se a mídia de armazenamento está ligada ou não e o número de setores da mídia de armazenamento, etc. Se for um aplicativo simples, não há necessidade de escrevê-lo. Seu protótipo de função é o seguinte:

  DRESULT disk_ioctl(BYTE drv, BYTE ctrl, VoiI*buff); De acordo com a definição do protótipo e os requisitos do nosso dispositivo de armazenamento em massa USB, podemos implementar as funções relacionadas ao controle do dispositivo de disco da seguinte forma:

/*USBH IO控制函数 */
static DRESULT USBH_ioctl(BYTE lun, BYTE cmd, void *buff)
{
 DRESULT res = RES_ERROR;
 MSC_LUNTypeDef info;

 switch (cmd)
 {
 /* Make sure that no pending write process */
 case CTRL_SYNC:
  res = RES_OK;
  break;

 /* Get number of sectors on the disk (DWORD) */
 case GET_SECTOR_COUNT :
  if(USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info) == USBH_OK)
  {
   *(DWORD*)buff = info.capacity.block_nbr;
   res = RES_OK;
  }
  else
  {
   res = RES_ERROR;
  }
  break;

 /* Get R/W sector size (WORD) */
 case GET_SECTOR_SIZE :
  if(USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info) == USBH_OK)
  {
   *(DWORD*)buff = info.capacity.block_size;
   res = RES_OK;
  }
  else
  {
   res = RES_ERROR;
  }
  break;

  /* Get erase block size in unit of sector (DWORD) */
 case GET_BLOCK_SIZE :

  if(USBH_MSC_GetLUNInfo(&hUsbHostFS, lun, &info) == USBH_OK)
  {
   *(DWORD*)buff = info.capacity.block_size / USB_DEFAULT_BLOCK_SIZE;
   res = RES_OK;
  }
  else
  {
   res = RES_ERROR;
  }
  break;

 default:
  res = RES_PARERR;
 }

 return res;
}

2.6. Obtenha a hora atual

  Função de relógio em tempo real get_fattime. Usado para obter a hora atual e retornar um número inteiro sem sinal de 32 bits. As informações do relógio estão contidas nesses 32 bits. Se você não usar um carimbo de data/hora, poderá retornar diretamente um número, como 0. Seu protótipo de função é o seguinte:

  DWORD get_fattime(Void);

  De acordo com a definição do protótipo e os requisitos do nosso dispositivo de armazenamento em massa USB, podemos implementar a função de aquisição do status do disco da seguinte forma:

/*读取时钟函数*/
DWORD get_fattime(void)
{

 return 0;

}

  Depois de concluir a redação dos seis programas acima, o trabalho de transplante está basicamente concluído. Você pode descobrir que o nome da função que implementamos parece ser diferente da função do protótipo. Isso ocorre principalmente para facilitar as operações quando existem vários dispositivos de armazenamento ao mesmo tempo. Podemos apenas chamar a função que implementamos na função de destino.

3. Teste de aplicação

  Concluímos o transplante do FatFS, agora vamos verificar se o transplante está correto. Para esse fim, vamos escrever um aplicativo para gravar dados em um arquivo em uma unidade flash USB e ler os dados do arquivo.

/* USB HOST MSC操作函数,这部分功能根据需求设定 */
static void MSC_Application(void)
{
  FRESULT res;                      /* FatFs函数返回值 */
  uint32_t byteswritten, bytesread;           /* 文件读写的数量 */
  uint8_t wtext[] = "This is STM32 working with FatFs!"; /* 写文件缓冲器 */
  uint8_t wtext2[] = "这是一个FatFs读写的例子!"; /* 写文件缓冲器 */
  uint8_t wtext3[] = "这是一个向文件追加数据的测试!"; /* 写文件缓冲器 */
  uint8_t rtext[100];                  /* 读文件缓冲器 */
  
  /* 注册文件系统对象到FatFs模块 */
  if(f_mount(&USBHFatFS, (TCHAR const*)USBHPath, 0) != FR_OK)
  {
    /* 错误处理 */
    Error_Handler();
  }
  else
  {
    /* 打开一个文件 */
    if(f_open(&USBHFile, "STM32.TXT", FA_OPEN_EXISTING | FA_WRITE) != FR_OK) 
    {
      /* 错误处理 */
      Error_Handler();
    }
    else
    {
      res=f_lseek(&USBHFile,f_size(&USBHFile));  //将指针指向文件末
      //res=f_lseek(&USBHFile,100);  //将指针指向文件末
      /* 写数据到文件 */
      res = f_write(&USBHFile, wtext, sizeof(wtext), (void *)&byteswritten);
      res = f_write(&USBHFile, "\r\n", sizeof("\r\n")-1, &byteswritten); 
      res = f_write(&USBHFile, wtext2, sizeof(wtext2), (void *)&byteswritten);
      res = f_write(&USBHFile, "\r\n", sizeof("\r\n")-1, &byteswritten);
      res = f_write(&USBHFile, wtext3, sizeof(wtext3), (void *)&byteswritten);
      res = f_write(&USBHFile, "\r\n", sizeof("\r\n")-1, &byteswritten);
      
      if((byteswritten == 0) || (res != FR_OK))
      {
        /* 错误处理 */
        Error_Handler();
      }
      else
      {
        /* 关闭文件 */
        f_close(&USBHFile);
        
        /* 打开文件读 */
        if(f_open(&USBHFile, "STM32.TXT", FA_READ) != FR_OK)
        {
          /* 错误处理 */
          Error_Handler();
        }
        else
        {
          /* 从文件读数据 */
          res = f_read(&USBHFile, rtext, sizeof(rtext), (void *)&bytesread);
          
          if((bytesread == 0) || (res != FR_OK))
          {
            /* 错误处理 */
            Error_Handler();
          }
          else
          {
            /* 关闭文件 */
            f_close(&USBHFile);
            
            /* 比较读和写的数据 */
            if((bytesread != byteswritten))
            {         
              /* 错误处理*/
              Error_Handler();
            }
            else
            {
              /* 无错误 */
              
            }
          }
        }
      }
    }
  }
  
  FATFS_UnLinkDriver(USBHPath);
}

  O arquivo que criamos primeiro na unidade flash USB foi denominado "STM32.TXT".No código-fonte acima, após criarmos o arquivo, nós o modificamos para abrir e existir. O arquivo criado é mostrado abaixo:

587ac6c302a82d319e86f68bad5b7d93.png

  Escreva "Este é o STM32 trabalhando com FatFs!"no arquivo STM32.TXT criado. Verificamos o conteúdo do arquivo e os resultados são os seguintes:

a0eeb8fc5cbc83fc3810c60f7db0d7b1.png

  Em seguida, tentamos anexar conteúdo a um arquivo já existente. Ainda é um arquivo STM32.TXT, após finalizarmos a operação verifique seu conteúdo abaixo:

cd0e81b774a9a6b0d5eed459e1a40750.png

  Neste ponto, concluímos o transplante e teste do sistema de arquivos FatFS.A partir dos resultados do teste, o transplante está correto, pelo menos nenhum problema foi encontrado em aplicativos simples.

4. Resumo do transplante

  Neste artigo, transplantamos o sistema de arquivos FatFS e realizamos um teste simples de leitura e gravação. A julgar pelos resultados dos testes, o FatFS sempre não teve problemas, pelo menos foi verificado que não há problemas com operações gerais de leitura e gravação.

  Quando portamos, consideramos a facilidade de operação quando várias unidades estão disponíveis ao mesmo tempo. A função de operação de E/S de disco que definimos precisa ser implementada com base no hardware real e, em seguida, a função de E/S de disco que escrevemos é chamada na função de retorno de chamada especificada pelo sistema. Isso permite a operação de várias unidades. Na verdade, isso também é recomendado no exemplo de E/S de disco fornecido pelo FatFS.

Declaração: O material deste artigo vem da Internet e os direitos autorais pertencem ao autor original. Se houver algum problema de direitos autorais com o trabalho, entre em contato comigo para excluí-lo.

------------  FIM  ------------

149fb987b27f4ab2834d0298eec51113.gif

●Coluna "Ferramentas incorporadas "

●Coluna "Desenvolvimento Incorporado"

●Coluna "Tutorial Keil"

●Tutoriais selecionados em colunas incorporadas

Siga a conta oficial e responda " Adicionar Grupo " para ingressar no grupo de troca técnica de acordo com as regras, e responda " 1024 " para visualizar mais conteúdo.

d84272eccdb5bb580f56f65f329b2747.jpeg

ec24d370f128e8184dc09c9b520af218.png

Clique em “ Leia o texto original ” para ver mais compartilhamentos.

Acho que você gosta

Origin blog.csdn.net/ybhuangfugui/article/details/133152873
Recomendado
Clasificación