Files
TAIXIN/sdk/lib/fs/fatfs/fatfs_test.c

563 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "sys_config.h"
#include "integer.h"
#include "diskio.h"
#include "ff.h"
#include <stdio.h>
#include "osal/sleep.h"
#include "typesdef.h"
#include "osal/task.h"
#include "osal/semaphore.h"
#include "osal/mutex.h"
#include "list.h"
#include "dev.h"
#include "sdhost.h"
#include "devid.h"
#include "osal/string.h"
#include "osal/work.h"
// #include "osal.h"
#define FAT_INFO_SHOW(...) //printf(__VA_ARGS__)
// #define FAT_TIME
#if FS_EN
static uint8_t fat_ready = 0;
uint8_t get_fat_isready()
{
return fat_ready;
}
void set_fat_ready(uint8_t ready)
{
fat_ready = ready;
}
static DSTATUS fatfs_status(void *status);
static DSTATUS fatfs_init(void *init_dev);
static DRESULT fatfs_read(void *dev, BYTE *buf, DWORD sector, UINT count);
static DRESULT fatfs_write(void *dev, BYTE *buf, DWORD sector, UINT count);
static DRESULT fatfs_ioctl(void *init_dev, BYTE cmd, void *buf);
uint32 get_sdhost_status(struct sdh_device *host);
uint32 sd_tran_stop(struct sdh_device *host);
static const struct fatfs_diskio sdcdisk_driver = {
.status = fatfs_status,
.init = fatfs_init,
.read = fatfs_read,
.write = fatfs_write,
.ioctl = fatfs_ioctl};
static FATFS fatfs[1];
DWORD get_fatbase(int num)
{
return fatfs[num].fatbase;
}
DWORD get_fatfree(int num)
{
DWORD fre_clust, fre_sect, tot_sect;
FATFS *fs = &fatfs[num];
fre_clust = fs->free_clst;
tot_sect = (fs->n_fatent - 2) * fs->csize;
fre_sect = fre_clust * fs->csize;
printf("%s %ldKB\n", __FUNCTION__, fre_sect >> 1);
return fre_sect >> 1;
}
static DSTATUS fatfs_status(void *status)
{
// FAT_INFO_SHOW ("fatfs_status_test\r\n");
uint32 err = get_sdhost_status(status);
return err;
}
static DSTATUS fatfs_init(void *init_dev){
printf ("fatfs_init_test\r\n");
uint32 err = get_sdhost_status(init_dev);
if(err)
{
err = sdhost_init(48 * 1000 * 1000, 0);
}
return err;
}
#if USE_FAT_CACHE
// 内存分配函数
static void *fat_malloc(int size)
{
#ifdef PSRAM_HEAP
return os_malloc_psram(size);
#else
return os_malloc(size);
#endif
}
// 内存释放函数
static void fat_free(void *p)
{
#ifdef PSRAM_HEAP
os_free_psram(p);
#else
os_free(p);
#endif
}
struct fat_data_t
{
// uint8 data[FAT_CACHE_SIZE * 512]; // 32KB 缓存
BYTE *data; // 32KB 缓存
DWORD start_sector; // 缓存起始扇区
DWORD fat_start; // FAT起始扇区
DWORD fat_end;
DWORD offset;
DWORD max_offset;
};
struct fat_cache_t
{
BYTE fat_info_ready; //
BYTE fat_init;
BYTE fs_type;
BYTE fs_fats;
DWORD fs_size;
DWORD fat_tick;
#ifdef FAT_TIME
os_timer_t fat_timer;
#else
struct os_work fat_wk;
#endif
struct os_mutex lock;
struct fat_data_t fat1;
};
struct fat_cache_t fat_cache = {
// lock和time初始化标志位1是未初始化0是已经初始化
.fat_init = 1,
.fat_info_ready = 1,
};
signed char update_fat_info(BYTE fmt, BYTE n_fats, DWORD sz_fat,DWORD fatbase, DWORD b_vol)
{
if (fat_cache.fat_init != RET_OK){
return RET_ERR;
}
os_mutex_lock(&fat_cache.lock, osWaitForever);
fat_cache.fs_type = fmt;
fat_cache.fs_fats = n_fats;
fat_cache.fs_size = sz_fat;
fat_cache.fat1.fat_start = fatbase;
fat_cache.fat1.fat_end = fat_cache.fat1.fat_start + fat_cache.fs_size - 1;
fat_cache.fat_info_ready = RET_OK;
// 计算逻辑地址(扇区号)
//UINT fat1_logical = fatbase - b_vol; // FAT1 logical start
//UINT fat2_logical = fat1_logical + sz_fat; // FAT2 logical start
// 计算物理地址(加上分区偏移)
//UINT partition_start = b_vol; // 分区起始扇区
//UINT fat1_physical = partition_start + fat1_logical;
//UINT fat2_physical = partition_start + fat2_logical;
// if (fat_cache.fs_type == FS_EXFAT) // FS_EXFAT文件系统不需要优化
// {
// fat_cache.fat_info_ready = 0;
// }
if (fmt == FS_FAT12)
FAT_INFO_SHOW("Filesystem Type: FS_FAT12 \r\n");
else if (fmt == FS_FAT16)
FAT_INFO_SHOW("Filesystem Type: FS_FAT16 \r\n");
else if (fmt == FS_FAT32)
FAT_INFO_SHOW("Filesystem Type: FS_FAT32 \r\n");
else if (fmt == FS_EXFAT)
FAT_INFO_SHOW("Filesystem Type: FS_EXFAT \r\n");
FAT_INFO_SHOW("Filesystem fat_num %u \r\n", n_fats);
FAT_INFO_SHOW("Filesystem fat_size %u \r\n", sz_fat);
FAT_INFO_SHOW("Physical Address ===> fat1_start %u , fat1_end %u \r\n", fat_cache.fat1.fat_start, fat_cache.fat1.fat_end);
FAT_INFO_SHOW("Logical Address ====> fat1_start %u , fat1_end %u \r\n", fat1_logical, fat1_logical + sz_fat - 1);
if (n_fats > 1) {
FAT_INFO_SHOW("Physical Address ===> fat2_start %u , fat2_end %u \r\n", fat2_physical, fat2_physical + sz_fat - 1);
FAT_INFO_SHOW("Logical Address ====> fat2_start %u , fat2_end %u \r\n", fat2_logical, fat2_logical + sz_fat - 1);
}
os_mutex_unlock(&fat_cache.lock);
return RET_OK;
}
void update_io_timestamp()
{
if (fat_cache.fat_init != RET_OK || fat_cache.fat_info_ready != RET_OK){
return;
}
os_mutex_lock(&fat_cache.lock, osWaitForever);
fat_cache.fat_tick = os_jiffies();
os_mutex_unlock(&fat_cache.lock);
}
// fat回写SD
static void fat_cache_sync(struct sdh_device *host)
{
struct sdh_device *sdh = NULL;
sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID);
if (fat_cache.fat_init != RET_OK || fat_cache.fat_info_ready != RET_OK){
return;
}
os_mutex_lock(&fat_cache.lock, osWaitForever);
FAT_INFO_SHOW("############# CTRL_SYNC max_offset %d\r\n", fat_cache.fat1.max_offset);
if (fat_cache.fat1.max_offset > 0)
{
sd_multiple_write((struct sdh_device *)host, fat_cache.fat1.start_sector, fat_cache.fat1.max_offset * 512, fat_cache.fat1.data);
if (fat_cache.fs_fats > 1)
{
sd_multiple_write((struct sdh_device *)host, (fat_cache.fat1.start_sector + fat_cache.fs_size), fat_cache.fat1.max_offset * 512, fat_cache.fat1.data);
}
fat_cache.fat1.max_offset = 0;
}
os_mutex_unlock(&fat_cache.lock);
}
#ifdef FAT_TIME
static void fat_loop(void *arg)
#else
static int32 fat_loop(struct os_work *work)
#endif
{
if (fat_cache.fat_init != RET_OK || fat_cache.fat_info_ready != RET_OK){
goto fat_loop_end;
}
uint8 ret = 0;
struct sdh_device *sdh = NULL;
sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID);
ret = os_mutex_lock(&sdh->lock, 0);
if (ret != RET_OK)
{
fat_cache.fat_tick = os_jiffies();
goto fat_loop_end; // 获取锁失败
}
os_mutex_unlock(&sdh->lock);
ret = os_mutex_lock(&fat_cache.lock, 0);
if (ret != RET_OK)
{
goto fat_loop_end; // 获取锁失败
}
// 检测到200ms没有操作SD卡并SD卡在线fat信息回写SD
if (os_jiffies() - fat_cache.fat_tick > 200 && SD_OFF != sdh->sd_opt)
{
fat_cache.fat_tick = os_jiffies();
if (fat_cache.fat1.max_offset > 0)
{
FAT_INFO_SHOW(" fat_loop write back max_offset %d\r\n", fat_cache.fat1.max_offset);
sd_multiple_write(sdh, fat_cache.fat1.start_sector, fat_cache.fat1.max_offset * 512, fat_cache.fat1.data);
if (fat_cache.fs_fats > 1) // 写入FAT2
{
sd_multiple_write(sdh, (fat_cache.fat1.start_sector + fat_cache.fs_size), fat_cache.fat1.max_offset * 512, fat_cache.fat1.data);
}
fat_cache.fat1.max_offset = 0;
}
}
os_mutex_unlock(&fat_cache.lock);
fat_loop_end:
#ifdef FAT_TIME
return;
#else
os_run_work_delay(work, 50);
return 0;
#endif
}
static void init_fat_cache(FATFS *fs)
{
if (update_fat_info(fs->fs_type, fs->n_fats, fs->fsize,fs->fatbase, fs->volbase) != RET_OK){
return;
}
FAT_INFO_SHOW("init_fat_cache \r\n");
struct sdh_device *sdh = NULL;
sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID);
// 初始化后第一次读fat1
fat_cache.fat1.start_sector = fs->fatbase;
sd_multiple_read(sdh, fat_cache.fat1.start_sector, FAT_CACHE_SIZE * 512, fat_cache.fat1.data);
}
static void del_fat_cache(void)
{
if (fat_cache.fat_init != RET_OK){
return;
}
fat_cache.fat_init = 1;
fat_cache.fat_info_ready = 1;
os_mutex_lock(&fat_cache.lock, osWaitForever);
FAT_INFO_SHOW("########### del_fat_cache \r\n");
#ifdef FAT_TIME
os_timer_stop(&fat_cache.fat_timer);
os_timer_del(&fat_cache.fat_timer);// 先卸载定时器
#else
os_work_cancle(&fat_cache.fat_wk,1);
#endif
// 释放fat缓存
if (fat_cache.fat1.data)
{
FAT_INFO_SHOW("%s %d fat free \r\n", __func__, __LINE__);
fat_free(fat_cache.fat1.data);
fat_cache.fat1.data = NULL;
}
os_mutex_unlock(&fat_cache.lock);
os_mutex_del(&fat_cache.lock);
}
static DRESULT read_from_fat_cache(void *dev, struct fat_data_t *cache, BYTE *buf, DWORD sector, UINT count)
{
int ret = 0;
if (fat_cache.fat_init != RET_OK || fat_cache.fat_info_ready != RET_OK){
return sd_multiple_read((struct sdh_device *)dev, sector, count * 512, buf);
}
os_mutex_lock(&fat_cache.lock, osWaitForever);
if (sector >= cache->start_sector && sector + count <= cache->start_sector + FAT_CACHE_SIZE)
{
// 从缓存读取
cache->offset = (sector - cache->start_sector);
memcpy(buf, &cache->data[cache->offset * 512], count * 512);
}
// 未命中缓存把旧缓存写入SD重新预读 16KB 到缓存
else
{
// 把旧缓存写入fat
if (cache->max_offset > 0)
{
FAT_INFO_SHOW("read_from_fat_cache write back max_offset %d sector %d\r\n", cache->max_offset, sector);
sd_multiple_write((struct sdh_device *)dev, cache->start_sector, cache->max_offset * 512, cache->data);
if (fat_cache.fs_fats > 1)
{
sd_multiple_write((struct sdh_device *)dev, (cache->start_sector + fat_cache.fs_size), cache->max_offset * 512, cache->data);
}
cache->max_offset = 0;
// memset(cache->data, 0, FAT_CACHE_SIZE * 512);
}
// 重新预读数据到缓存
ret = sd_multiple_read((struct sdh_device *)dev, sector, FAT_CACHE_SIZE * 512, cache->data);
cache->start_sector = sector;
memcpy(buf, &cache->data[0], count * 512);
}
// __end:
os_mutex_unlock(&fat_cache.lock);
return ret;
}
static DRESULT write_to_fat_cache(void *dev, struct fat_data_t *cache, BYTE *buf, DWORD sector, UINT count)
{
int ret = 0;
if (fat_cache.fat_init != RET_OK || fat_cache.fat_info_ready != RET_OK){
return sd_multiple_write((struct sdh_device *)dev, sector, count * 512, buf);
}
os_mutex_lock(&fat_cache.lock, osWaitForever);
// 检查是否命中缓存
if (sector >= cache->start_sector && sector + count <= cache->start_sector + FAT_CACHE_SIZE)
{
cache->offset = (sector - cache->start_sector);
memcpy(&cache->data[cache->offset * 512], buf, count * 512);
if (cache->max_offset < (cache->offset + 1))
{
cache->max_offset = cache->offset + 1;
}
}
else
{
// 把旧缓存写入fat
if (cache->max_offset > 0)
{
FAT_INFO_SHOW("write_to_fat_cache write back max_offset %d sector %d\r\n", cache->max_offset, sector);
sd_multiple_write((struct sdh_device *)dev, cache->start_sector, cache->max_offset * 512, cache->data);
if (fat_cache.fs_fats > 1)
{
sd_multiple_write((struct sdh_device *)dev, (cache->start_sector + fat_cache.fs_size), cache->max_offset * 512, cache->data);
}
cache->max_offset = 0;
// memset(cache->data, 0, FAT_CACHE_SIZE * 512);
}
// 重新预读数据到缓存
ret = sd_multiple_read((struct sdh_device *)dev, sector, FAT_CACHE_SIZE * 512, cache->data);
cache->start_sector = sector;
cache->offset = 0;
memcpy(&cache->data[cache->offset * 512], buf, count * 512);
if (cache->max_offset < (cache->offset + 1))
{
cache->max_offset = cache->offset + 1;
}
}
// __end:
os_mutex_unlock(&fat_cache.lock);
return ret;
}
#endif
DRESULT fatfs_read(void *dev, BYTE *buf, DWORD sector, UINT count)
{
#if USE_FAT_CACHE
update_io_timestamp();
if (sector >= fat_cache.fat1.fat_start && sector <= fat_cache.fat1.fat_end)
{
return read_from_fat_cache((struct sdh_device *)dev, &fat_cache.fat1, buf, sector, count);
}
#endif
return sd_multiple_read((struct sdh_device *)dev, sector, count * 512, buf);
}
static DRESULT fatfs_write(void *dev, BYTE *buf, DWORD sector, UINT count)
{
#if USE_FAT_CACHE
update_io_timestamp();
if (sector >= fat_cache.fat1.fat_start && sector <= fat_cache.fat1.fat_end)
{
return write_to_fat_cache((struct sdh_device *)dev, &fat_cache.fat1, buf, sector, count);
}
#endif
return sd_multiple_write((struct sdh_device *)dev, sector, count * 512, buf);
}
extern unsigned int sd_dwCap;
extern uint32 fatfs_sd_tran_stop(struct sdh_device *host);
static DRESULT fatfs_ioctl(void *init_dev, BYTE cmd, void *buf)
{
uint8 ret = RES_OK;
switch (cmd)
{
case CTRL_SYNC:
fatfs_sd_tran_stop(init_dev);
#if USE_FAT_CACHE
fat_cache_sync(init_dev);
#endif
break;
case GET_SECTOR_COUNT:
*(DWORD *)buf = sd_dwCap * 2;
ret = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD *)buf = 512;
ret = RES_OK;
break;
case GET_BLOCK_SIZE:
*(DWORD *)buf = 4;
// printf("*0B:%d\n",*B);
ret = RES_OK;
break;
default:
ret = RES_ERROR; // not finish
printf("rtos_sd_ioctl err\n");
break;
}
return ret;
}
bool fatfs_register()
{
int ret = 1;
struct sdh_device *fatfs_sdh;
// printf(">>>>>>>>>> enter %s test\r\n", __func__);
fatfs_sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID);
#if USE_FAT_CACHE
if (fat_cache.fat_init)
{
// 分配 fat1 缓存
fat_cache.fat1.data = fat_malloc(FAT_CACHE_SIZE * 512);
if( fat_cache.fat1.data != NULL &&
os_mutex_init(&fat_cache.lock) == RET_OK &&
#ifdef FAT_TIME
os_timer_init(&fat_cache.fat_timer, fat_loop, OS_FAT_TIMER_MODE_PERIODIC, 0) == RET_OK
#else
OS_WORK_INIT(&fat_cache.fat_wk, fat_loop, 0) == RET_OK
#endif
)
{
fat_cache.fat_init = RET_OK;
FAT_INFO_SHOW("fat_init success\r\n");
#ifdef FAT_TIME
os_timer_start(&fat_cache.fat_timer, 50);
#else
os_run_work_delay(&fat_cache.fat_wk, 50);
#endif
}
else
{
os_printf("fat init err \r\n");
}
}
#endif
if (fatfs_sdh)
{
fatfs_register_drive(0, (struct fatfs_diskio*)&sdcdisk_driver, fatfs_sdh);
ret = f_mount(&fatfs[0], _SYSDSK_, 1);
if (ret)
{
printf("%s ret:%d\n", __FUNCTION__, ret);
f_mount(NULL, _SYSDSK_, 0);
return ret;
}
FAT_INFO_SHOW("f_mount success\r\n");
set_fat_ready(1);
#if USE_FAT_CACHE
init_fat_cache(&fatfs[0]);
#endif
}
return ret;
}
void fatfs_unregister()
{
int ret = 1;
FAT_INFO_SHOW(">>>>>>>>>>enter %s test\r\n", __func__);
struct sdh_device *fatfs_sdh;
fatfs_sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID);
if (fatfs_sdh)
{
fatfs_register_drive(0, (struct fatfs_diskio*)&sdcdisk_driver, fatfs_sdh);
ret = f_mount(NULL, _SYSDSK_, 0);
if (ret)
{
printf("%s ret:%d\n", __FUNCTION__, ret);
return;
}
set_fat_ready(0);
#if USE_FAT_CACHE
del_fat_cache();
#endif
}
}
#endif