FatFS + Virtual Memory in RAM

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!

 

I'm trying to test the FatFS in a virtual memory disk with SAMD21 Xplained pro. I found no example on Virtual Memory ASF module but found FatFS with MMC. So I modified the example code to use the virtual memory "disk". I can't make it work, when I try to open a file for writing some text, I get a FR_NO_FILESYSTEM error.

 

this are the steps that I did to test the modules:

1- included the virtual memory ASF module, 

2- changed the conf_access.h to use the virtual memory

#define LUN_0                ENABLE   //!< On-Chip Virtual Memory.
#define LUN_1                DISABLE   //!< AT45DBX Data Flash.
#define LUN_2                DISABLE    //!< SD/MMC Card over Slot 0
#define LUN_3                DISABLE   //!< Spare
#define LUN_4                DISABLE   //!< Spare
#define LUN_5                DISABLE   //!< Spare
#define LUN_6                DISABLE   //!< Spare
#define LUN_7                DISABLE   //!< Spare
#define LUN_USB              DISABLE   //!< Host Mass-Storage Memory.

enabled access mem to ram in the conf_virtual_mem.h

#define ACCESS_MEM_TO_RAM  true

the main code is f_mount, f_open, f_put. 

 

int main(void)
{
	char test_file_name[] = "0:test.txt";
	FRESULT res;
	FATFS fs;
	FIL file_object;


	system_init();
	delay_init();
	cdc_uart_init();

	delay_ms(1000);

	irq_initialize_vectors();
	cpu_irq_enable();


	printf("Mount disk (f_mount)...\r\n");
	memset(&fs, 0, sizeof(FATFS));
	res = f_mount(LUN_ID_VIRTUAL_MEM, &fs);
	printf("f_mount: [ret]-> %d \r\n", res);

	printf("Create a file (f_open)...\r\n");
	res = f_open(&file_object,test_file_name, FA_WRITE | FA_CREATE_ALWAYS );
	if (res != FR_OK) {
		printf("f_open: [ret]-> %d\r\n", res);
	}
	else
	{
		printf("[OK]\r\n");
		
		printf("Write to test file (f_puts)...\r\n");
		if (0 == f_puts(&file_object, "Test \n")) {
			f_close(&file_object);
			printf("[FAIL]\r\n");
		}
		printf("[OK]\r\n");
		f_close(&file_object);
		printf("Test is successful.\n\r");
	}
	
	while(1);
}

and the output is 

 

Mount disk (f_mount)...
f_mount: [ret]-> 0
Create a file (f_open)...
f_open: [ret]-> 13

There is no example on Virtual Memory. I don't know if I'm missing some initialization. 

 

I cant'f find what I'm missing. 

 

Any toughts?

 

thanks,

Jorge

This topic has a solution.
Last Edited: Fri. Apr 28, 2017 - 12:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sdcards are usually formatted to fat32 from the factory. No such luck with your ram. Fatfs has a mkfs function (make filesystem).

Second time this week!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Sdcards are usually formatted to fat32 from the factory. No such luck with your ram. Fatfs has a mkfs function (make filesystem). Second time this week!

 

yesterday, after posting, I added the f_mkfs, but now the error is disk error:

	printf("Mount disk (f_mount)...\r\n");
	memset(&fs, 0, sizeof(FATFS));
	
	res = f_mount(LUN_ID_VIRTUAL_MEM, &fs);
	printf("f_mount: [ret]-> %d \r\n", res);
	
	
	res = f_mkfs(LUN_ID_VIRTUAL_MEM,0,512);
	printf("f_mkfs: [ret]-> %d \r\n", res);
	
	printf("Create a file (f_open)...\r\n");
	res = f_open(&file_object,test_file_name, FA_WRITE | FA_CREATE_ALWAYS );
	if (res != FR_OK) {
		printf("f_open: [ret]-> %d\r\n", res);
	}
	else
	{
		printf("[OK]\r\n");
		
		printf("Write to test file (f_puts)...\r\n");
		if (0 == f_puts(&file_object, "Test SD/MMC stack\n")) {
			f_close(&file_object);
			printf("[FAIL]\r\n");
		}
		printf("[OK]\r\n");
		f_close(&file_object);
		printf("Test is successful.\n\r");
	}

I added also some debug and found that when there is a call to disk_ioctl inside f_mkfs that returns "disk error". I'm debuggin, maybe I will get the answer later and post it here. But there must be a simple solution that I'm not seeing, debuggin inside the fatfs code is maybe is something that I shouldn't be doing I'm looking for something simple to test like ASF.

 

Reset!
Mount disk (f_mount)...
f_mount: [ret]-> 0
stat: 0x0
llama a diskioctl: 0x0 0x20002C4C 0x42BD
diskioctl: 0x0
disk error!
f_mkfs: [ret]-> 1
Create a file (f_open)...
f_open: [ret]-> 13

 

digging into the code, I found that the

 

#if _USE_MKFS && !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* Create File System on the Drive                                       */
/*-----------------------------------------------------------------------*/
#define N_ROOTDIR	512		/* Number of root dir entries for FAT12/16 */
#define N_FATS		1		/* Number of FAT copies (1 or 2) */


FRESULT f_mkfs (
	BYTE drv,		/* Logical drive number */
	BYTE sfd,		/* Partitioning rule 0:FDISK, 1:SFD */
	UINT au			/* Allocation unit size [bytes] */
)
{
	static const WORD vst[] = { 1024,   512,  256,  128,   64,    32,   16,    8,    4,    2,   0};
	static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
	BYTE fmt, md, sys, *tbl, pdrv, part;
	DWORD n_clst, vs, n, wsect;
	UINT i;
	DWORD b_vol, b_fat, b_dir, b_data;	/* LBA */
	DWORD n_vol, n_rsv, n_fat, n_dir;	/* Size */
	FATFS *fs;
	DSTATUS stat;
	
	uint8_t jtz;


	/* Check mounted drive and clear work area */
	if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
	if (sfd > 1) return FR_INVALID_PARAMETER;
	if (au & (au - 1)) return FR_INVALID_PARAMETER;
	fs = FatFs[drv];
	if (!fs) return FR_NOT_ENABLED;
	fs->fs_type = 0;
	pdrv = LD2PD(drv);	/* Physical drive */
	part = LD2PT(drv);	/* Partition (0:auto detect, 1-4:get from partition table)*/

	/* Get disk statics */
	stat = disk_initialize(pdrv);
	printf("stat: 0x%X\n",stat);
	if (stat & STA_NOINIT) return FR_NOT_READY;
	if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
#if _MAX_SS != 512					/* Get disk sector size */
	if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
		return FR_DISK_ERR;
#endif
	if (_MULTI_PARTITION && part) {
		/* Get partition information from partition table in the MBR */
		if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
		if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
		tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
		if (!tbl[4]) return FR_MKFS_ABORTED;	/* No partition? */
		b_vol = LD_DWORD(tbl+8);	/* Volume start sector */
		n_vol = LD_DWORD(tbl+12);	/* Volume size */
	} else {
		/////////////////////////// HERE //////////////////////
		///////////////////////////      //////////////////////
		/* Create a partition in this function */
		printf("llama a diskioctl: 0x%X 0x%X 0x%X \n",jtz);
		jtz = disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol);
		printf("diskioctl: 0x%X\n",jtz);

		if ( jtz != RES_OK || n_vol < 128)
		{
			printf("disk error!\n");
			return FR_DISK_ERR;
		}
		b_vol = (sfd) ? 0 : 63;		/* Volume start sector */
		n_vol -= b_vol;				/* Volume size */
	}

	if (!au) {				/* AU auto selection */
		vs = n_vol / (2000 / (SS(fs) / 512));
		for (i = 0; vs < vst[i]; i++) ;
		au = cst[i];
	}
	au /= SS(fs);		/* Number of sectors per cluster */
	if (au == 0) au = 1;
	if (au > 128) au = 128;

	/* Pre-compute number of clusters and FAT syb-type */
	n_clst = n_vol / au;
	fmt = FS_FAT12;
	if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
	if (n_clst >= MIN_FAT32) fmt = FS_FAT32;

	/* Determine offset and size of FAT structure */
	if (fmt == FS_FAT32) {
		n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
		n_rsv = 32;
		n_dir = 0;
	} else {
		n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
		n_fat = (n_fat + SS(fs) - 1) / SS(fs);
		n_rsv = 1;
		n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
	}
	b_fat = b_vol + n_rsv;				/* FAT area start sector */
	b_dir = b_fat + n_fat * N_FATS;		/* Directory area start sector */
	b_data = b_dir + n_dir;				/* Data area start sector */
	if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED;	/* Too small volume */

	/* Align data start sector to erase block boundary (for flash memory media) */
	if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
	n = (b_data + n - 1) & ~(n - 1);	/* Next nearest erase block from current data start */
	n = (n - b_data) / N_FATS;
	if (fmt == FS_FAT32) {		/* FAT32: Move FAT offset */
		n_rsv += n;
		b_fat += n;
	} else {					/* FAT12/16: Expand FAT size */
		n_fat += n;
	}

	/* Determine number of clusters and final check of validity of the FAT sub-type */
	n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
	if (   (fmt == FS_FAT16 && n_clst < MIN_FAT16)
		|| (fmt == FS_FAT32 && n_clst < MIN_FAT32))
		return FR_MKFS_ABORTED;

	switch (fmt) {	/* Determine system ID for partition table */
	case FS_FAT12:	sys = 0x01; break;
	case FS_FAT16:	sys = (n_vol < 0x10000) ? 0x04 : 0x06; break;
	default: 		sys = 0x0C;
	}

	if (_MULTI_PARTITION && part) {
		/* Update system ID in the partition table */
		tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
		tbl[4] = sys;
		if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
		md = 0xF8;
	} else {
		if (sfd) {	/* No patition table (SFD) */
			md = 0xF0;
		} else {	/* Create partition table (FDISK) */
			mem_set(fs->win, 0, SS(fs));
			tbl = fs->win+MBR_Table;	/* Create partiton table for single partition in the drive */
			tbl[1] = 1;						/* Partition start head */
			tbl[2] = 1;						/* Partition start sector */
			tbl[3] = 0;						/* Partition start cylinder */
			tbl[4] = sys;					/* System type */
			tbl[5] = 254;					/* Partition end head */
			n = (b_vol + n_vol) / 63 / 255;
			tbl[6] = (BYTE)((n >> 2) | 63);	/* Partiiton end sector */
			tbl[7] = (BYTE)n;				/* End cylinder */
			ST_DWORD(tbl+8, 63);			/* Partition start in LBA */
			ST_DWORD(tbl+12, n_vol);		/* Partition size in LBA */
			ST_WORD(fs->win+BS_55AA, 0xAA55);	/* MBR signature */
			if (disk_write(pdrv, fs->win, 0, 1) != RES_OK)	/* Write it to the MBR sector */
				return FR_DISK_ERR;
			md = 0xF8;
		}
	}

	/* Create BPB in the VBR */
	tbl = fs->win;							/* Clear sector */
	mem_set(tbl, 0, SS(fs));
	mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
	i = SS(fs);								/* Sector size */
	ST_WORD(tbl+BPB_BytsPerSec, i);
	tbl[BPB_SecPerClus] = (BYTE)au;			/* Sectors per cluster */
	ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);		/* Reserved sectors */
	tbl[BPB_NumFATs] = N_FATS;				/* Number of FATs */
	i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR;	/* Number of rootdir entries */
	ST_WORD(tbl+BPB_RootEntCnt, i);
	if (n_vol < 0x10000) {					/* Number of total sectors */
		ST_WORD(tbl+BPB_TotSec16, n_vol);
	} else {
		ST_DWORD(tbl+BPB_TotSec32, n_vol);
	}
	tbl[BPB_Media] = md;					/* Media descriptor */
	ST_WORD(tbl+BPB_SecPerTrk, 63);			/* Number of sectors per track */
	ST_WORD(tbl+BPB_NumHeads, 255);			/* Number of heads */
	ST_DWORD(tbl+BPB_HiddSec, b_vol);		/* Hidden sectors */
	n = get_fattime();						/* Use current time as VSN */
	if (fmt == FS_FAT32) {
		ST_DWORD(tbl+BS_VolID32, n);		/* VSN */
		ST_DWORD(tbl+BPB_FATSz32, n_fat);	/* Number of sectors per FAT */
		ST_DWORD(tbl+BPB_RootClus, 2);		/* Root directory start cluster (2) */
		ST_WORD(tbl+BPB_FSInfo, 1);			/* FSInfo record offset (VBR+1) */
		ST_WORD(tbl+BPB_BkBootSec, 6);		/* Backup boot record offset (VBR+6) */
		tbl[BS_DrvNum32] = 0x80;			/* Drive number */
		tbl[BS_BootSig32] = 0x29;			/* Extended boot signature */
		mem_cpy(tbl+BS_VolLab32, "NO NAME    " "FAT32   ", 19);	/* Volume label, FAT signature */
	} else {
		ST_DWORD(tbl+BS_VolID, n);			/* VSN */
		ST_WORD(tbl+BPB_FATSz16, n_fat);	/* Number of sectors per FAT */
		tbl[BS_DrvNum] = 0x80;				/* Drive number */
		tbl[BS_BootSig] = 0x29;				/* Extended boot signature */
		mem_cpy(tbl+BS_VolLab, "NO NAME    " "FAT     ", 19);	/* Volume label, FAT signature */
	}
	ST_WORD(tbl+BS_55AA, 0xAA55);			/* Signature (Offset is fixed here regardless of sector size) */
	if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK)	/* Write it to the VBR sector */
		return FR_DISK_ERR;
	if (fmt == FS_FAT32)							/* Write backup VBR if needed (VBR+6) */
		disk_write(pdrv, tbl, b_vol + 6, 1);

	/* Initialize FAT area */
	wsect = b_fat;
	for (i = 0; i < N_FATS; i++) {		/* Initialize each FAT copy */
		mem_set(tbl, 0, SS(fs));			/* 1st sector of the FAT  */
		n = md;								/* Media descriptor byte */
		if (fmt != FS_FAT32) {
			n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
			ST_DWORD(tbl+0, n);				/* Reserve cluster #0-1 (FAT12/16) */
		} else {
			n |= 0xFFFFFF00;
			ST_DWORD(tbl+0, n);				/* Reserve cluster #0-1 (FAT32) */
			ST_DWORD(tbl+4, 0xFFFFFFFF);
			ST_DWORD(tbl+8, 0x0FFFFFFF);	/* Reserve cluster #2 for root dir */
		}
		if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
			return FR_DISK_ERR;
		mem_set(tbl, 0, SS(fs));			/* Fill following FAT entries with zero */
		for (n = 1; n < n_fat; n++) {		/* This loop may take a time on FAT32 volume due to many single sector writes */
			if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
				return FR_DISK_ERR;
		}
	}

	/* Initialize root directory */
	i = (fmt == FS_FAT32) ? au : n_dir;
	do {
		if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
			return FR_DISK_ERR;
	} while (--i);

#if _USE_ERASE	/* Erase data area if needed */
	{
		DWORD eb[2];

		eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
		disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb);
	}
#endif

	/* Create FSInfo if needed */
	if (fmt == FS_FAT32) {
		ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
		ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
		ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);	/* Number of free clusters */
		ST_DWORD(tbl+FSI_Nxt_Free, 2);				/* Last allocated cluster# */
		ST_WORD(tbl+BS_55AA, 0xAA55);
		disk_write(pdrv, tbl, b_vol + 1, 1);	/* Write original (VBR+1) */
		disk_write(pdrv, tbl, b_vol + 7, 1);	/* Write backup (VBR+7) */
	}

	return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
}

thanks!!

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's a lot of stuff you haven't shown. A quick google found this:
https://github.com/alexeicolin/sysbios/blob/master/packages/ti/sysbios/fatfs/ramdisk.c

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

There's a lot of stuff you haven't shown. A quick google found this:
https://github.com/alexeicolin/s...

thank you !!! I will check the code and try it. But maybe I will have the same issue that I have found:

After hours of debbuging, I realized that there is a condition in the code of the FatFS f_mkfs function that is impossible to pass with Virtual RAM disk, 

 

if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) return FR_DISK_ERR;

 

the SECTOR_COUNT of a virtual ram disk of 4K (default) is 8 (512*8=4K). A virtual ram disk of 128 sectors of 512 bytes is 64K, and the minium sector size is 512 bytes. There is no cortex-m0 uC with that amount of ram, so, maybe the RAM disk will never work with this implementation of fatfs in a small uC as ATSAMD21J18.

Thanks

 

 

Last Edited: Thu. Apr 27, 2017 - 01:23 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you'll find the limitation is with the FAT filesystem itself - it needs to have storage for the directory, the file allocation table and the master boot record. That's your 4k gone already.
One would have to question the need of a file system with such a small amount of storage.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
I think you'll find the limitation is with the FAT filesystem itself - it needs to have storage for the directory, the file allocation table and the master boot record. That's your 4k gone already. One would have to question the need of a file system with such a small amount of storage.
 

 

It's not really necesary, in my project I have to send data over GSM network. If the network is available, I have a ram queue of messages, and if network isn't available, I will store messages in a fat filesystem on a AT45xxx memory. It would be nice the same storage method but I will have to use maybe a vector/list for ram.

 

thank you !!