Saturday, February 28, 2009

Fat32 complete library in asm language

Observing that the file system created by me is almost identical to FAT32, i decided to convert to FAT32, this library work with clusters from 256 bytes to 32768 bytes autodetect from storage device.

This library is in asm language.

This file system is designed for double buffered (a buffer to the Allocation Table and a data buffer) this method of using separate buffers increase the rate of transfer to the storage device.

The buffer’s separation between allocation table and the data, makes that at each change of the data cluster not to charge the next cluster index from storage device. In this case, the index is token from allocation table’s buffer, if this is inside the sector memorized inside buffer. If this is not inside the sector of the buffer, then will be saved the buffer in allocation table (in case that inside the buffer has been made a modification), and then will be loaded in the sector where the index is.

In this way can be made with the data buffer. The pointer can be putted at an particular offset from open file, and then, from the address of the pointer can be read byte with byte, the pointer been incremented automatically. The same will be the sectors inside the buffer, those will be changed automatically. It doesn’t matter for user which cluster or bit must be read, because everything is done automatically. User must set the address of the file needed and the pointer of the address of the byte inside the file.

Done functions:
-Go to file/folder ( address in clusters )
-Go to next file/folder in current directory ( this function return Flag T in Sreg = 0 if the pointer is on bottom of the list else return 1)
-Go to forward file folder in current directory ( this function return Flag T in Sreg = 0 if the pointer is on top of the list else return 1)
-Read address on pointed file/folder ( in clusters )
-Read short name of pointed file/folder ( string 11 char )
-Read full name of pointed file/folder ( string max 128 char )
-Read byte by byte the file opened ( offset of byte in file ) with autoincrement pointer
-Write byte by byte in the file opened ( offset of byte in file ) with autoincrement pointer ( this function work with append in file and have property to enlarge the size of file )
-Read pointed file size (in bytes)
-Write pointed file size = current pointer
-Read pointed file attribute
-Write pointed file attribute
-Read pointer in opened file
-Write pointer in opened file
-Create file with short name converted from long name( Creating with long name not completed )
-CloseFile ( when the file is closed if the pointer in file is bigger to actual size of file , the actual size of file = pointer position in file ( in read mode is not possible to point to an byte address bigger to file size but in write mode this is possible because the file is auto enlarged )

The terminal have next functions:
+ :
Go Down one file folder and read short and long file name.
- :
Go Up one file folder and read short and long file name.
Enter :
1) Go to selected folder,
2) Open selected file,
3) Close opened file.
Esc :
Close opened file
p :
Enter in write long file name, and Enter will convert from long filename to short filename
c :
Create file with converted short filename


Performance obtained with ATmega640 at 16 Mhz and SPI hardware at 8Mhz:

Write SD Card with 512 Bytes/cluster = 48659 Bytes/s
Write SD Card with 4096 Bytes/cluster = 40163 Bytes/s
Read SD Card with 512 Bytes/cluster = 70286 Bytes/s
Read SD Card with 4096 Bytes/cluster = 56229 Bytes/s

Transfer rate depends on the device storage and on fragmentation.
The flash used not include the terminal

Resources for maxim 512 bytes/cluster:
Flash= 3220 Bytes ( Only read section )
Flash= 5042 Bytes ( Read and write sections )
Ram for allocation table management= 542
Ram for data management= 629 (512Bytes (Data Buffer)+ 64 (Bytes String Long Name) + 11Bytes (String Short Name) + Variables )
Total Ram= 1171Bytes

Resources for maxim 4096 bytes/cluster:
Flash= 3220 Bytes ( Only read section )
Flash= 5042 Bytes ( Read and write sections )
Ram for allocation table management= 542
Ram for data management= 4213 (4096Bytes (Data Buffer)+ 64 Bytes (String Long Name) + 11Bytes (String Short Name) + Variables )
Total Ram= 4755 Bytes

The ram size is set by user because the maximum size of cluster is set by ram buffer data cluster

The data management library is a dynamic library ( That means this library can be open multiple times, and when you call the library in Z must be the beginning address of RAM to work with ) for this i wrote the ram size table occupied by allocation library and data management library separately

In conclusion we can work with multiple open files using a single library written in flash that can work with multiple sections of ram

Operating principle:
This block function is one example only for 512 Bytes/Cluster Fat32 formats for other cluster dimension the ram allocation is different.


Fig1


In this moment i work to create and allocation table library from static library to dynamic library

These two libraries ( allocation table and data section ) will be in 2 variants:
1) A library will have only buffer for data which can be put on the controllers with ram more than 655Bytes
2) A library that does not include buffers (will lose the stats of dynamic library) but which can be put on the controllers that have the minimum 128Bytes of ram
____________________________________________________________________

This library is concept to work with only one buffer and work fine to my MP3 players at 5Mhz with 320Kb/s melody with one artifice, and from this moment this library is open source
This library use 3016Bytes of flash and 655Bytes of ram memory
The up bloc description in Fig1 can by applied and for this library

1)Fat32_DataInit
2)Fat32_ReadByte
3)Fat32_GoToRoot
4)Fat32_GoToFile
5)Fat32_ResetDirPointer
6)Fat32_IncrementDirPointer
7)Fat32_DecrementDirPointer
8)Fat32_GetShortFileName
9)Fat32_GetLongFileName
10)Fat32_GetFileAdress
11)Fat32_ReadFileSize
12)Fat32_ReadFileAttr
13)Fat32_WritePointerInFile
14)Fat32_ReadPointerInFile
15)Fat32_OpenPointedFileFolder
16)Fat32_CloseFile

Last update 17-06-2009
Download fat32 read only library for atmega64
Download fat32 read only library for atmega8

Now this driver is updated and included in my ASM_SDK here

For support post a comment

16 comments:

Nischay, India said...

Hello Morgoth,

Thanks for Excellent Fat32 Library in ASM. Currently i am doing a project of playing raw wav data stored on SD card(No FAT system- just copying raw data using disk image copy)using Atmeg8, i don't need FAT system, i require to Init, Read & write from SD card sectors, pl.need your help.

Morgoth said...

For writing raw data to the SD card is very simple with only driver included in this library ,that is separately.

.Include "SdDriver.asm"

For initiate SD card call initiating routine from SD driver like this:

CallLibrary _SDDriver,Sd_DriverInit

Fill 512 Bytes of ram with data to be write to the first sector on buffer on this location: "512BytesBufferLocationInRam"

After this, fallow this routines:

Ldi R16,0
Ldi R17,0
Ldi R18,0
Ldi R19,0
Ldi Xl,Low(512BytesBufferLocationInRam)
Ldi Xh,High(512BytesBufferLocationInRam)
Ldi Yl,Low(MMC_SECTOR_SIZE)
Ldi Yh,High(MMC_SECTOR_SIZE)
CallLibrary _SDDriver,Sd_WriteSector

After this fill another 512 Bytes of data to the same buffer

And falow this routines

Ldi R16,1
Ldi R17,0
Ldi R18,0
Ldi R19,0
Ldi Xl,Low(512BytesBufferLocationInRam)
Ldi Xh,High(512BytesBufferLocationInRam)
Ldi Yl,Low(MMC_SECTOR_SIZE)
Ldi Yh,High(MMC_SECTOR_SIZE)
CallLibrary _SDDriver,Sd_WriteSector

Etc.

R16:R17:R18:R19 is the sector number on the SD card

If you want to edit one byte or multiple bytes from one Page from SD card proceed like this:

Ldi R16,0
Ldi R17,0
Ldi R18,0
Ldi R19,0
Ldi Xl,Low(512BytesBufferLocationInRam)
Ldi Xh,High(512BytesBufferLocationInRam)
Ldi Yl,Low(MMC_SECTOR_SIZE)
Ldi Yh,High(MMC_SECTOR_SIZE)
CallLibrary _SDDriver,Sd_ReadSector

Bodify bytes on buffer
....
....
....

Ldi R16,0
Ldi R17,0
Ldi R18,0
Ldi R19,0
Ldi Xl,Low(512BytesBufferLocationInRam)
Ldi Xh,High(512BytesBufferLocationInRam)
Ldi Yl,Low(MMC_SECTOR_SIZE)
Ldi Yh,High(MMC_SECTOR_SIZE)
CallLibrary _SDDriver,Sd_WriteSector

Sd_WriteSector and Sd_ReadSector functions return intact R16:R17:R18:R19 registry

Nischay, India said...

Dear Morgoth, Thanks a million for showing the steps in detail !
1)the "512BytesBufferLocationInRam" has to be created in SRAM under.DSEG, right?(iam using Atmega8)

2)your code "sdDriver.asm" has "PORTH" variable, what should i do with it?

3)their is also "slepS" subroutine- do i have to include that too?

4)is error handling done in the "sdDriver.asm"

5)as you said "R16:R17:R18:R19 is the sector number on the SD card" these are in Hex or decimal ?

Sorry for bothering you so much and taking your time, please clarify my doubts.

and also can you pl.show me how to do a 512 counter (to store 512 buffer in SRAM)

Morgoth said...

For question 1:
This buffer can be declared like this
.Dseg
512BytesBufferLocationInRam: .Byte 512
.Cseg

This"512BytesBufferLocationInRam" is a generic name, an can be other name because the avr studio don't accept first char one number.

For question 2:
Yes is PORTH because this fat32 library uses only read section and i not actualize writing section to the test board, but now i actualized and the writing section and is ready to download.

For question 3:
This function is a delay function and is absolutely necessarily.

For question 4:
"is error handling done in the "sdDriver.asm"" this error is because the atmega 8 i not have Call and Jmp instruction and i have only Rcall and Rjmp instruction.

For question 5:

This registri can be writed with numbers betwen 0 and 4294967295 like this:

Ldi R16,Low(Sector number)
Ldi R17,Byte2(Sector number)
Ldi R18,Byte3(Sector number)
Ldi R19,Byte4(Sector number)

For increment this 32 bit pointer use this routines:

Subi R16,Low(-1)
Sbci R17,Byte2(-1)
Sbci R18,Byte3(-1)
Sbci R19,Byte4(-1)

For decrement this 32 bit pointer use this routines:

Subi R16,Low(1)
Sbci R17,Byte2(1)
Sbci R18,Byte3(1)
Sbci R19,Byte4(1)


For count 512 use routines like this:

Ldi Xl,Low(512)
Ldi Xh,High(512)
Ldi Yl,Low(512BytesBufferLocationInRam)
Ldi Yl,High(512BytesBufferLocationInRam)
LoopWrite512BytesToTheBuffer:
Ldi R16,Data to be written
St Y+,R16
Sbiw Xl:Xh,1
Brne LoopWrite512BytesToTheBuffer

X Double register is decremented until is 0.
In Y pointer is write data to be store.
In R16 load data to be stored in Pointed byte to the buffer.

Nischay,India said...

Dear Morgoth, Thanks a lot for quick replies and showing some very useful rotuines!
i am well versed with 8051 micro and AVR is new to me.
in subroutines "SdDriverWriteInit:" and
"SdDriverReadInit:" you have used Ldi Xl,Low(DelayWriteCommand)
Ldi Xh,High(DelayWriteCommand) and Ldi Xl,Low(DelayReadCommand)
Ldi Xh,High(DelayReadCommand)
and in .equ you have used Delaywrite command = DelayReadcommand = 256, should i use 256 or use 512 as buffer size?

also, could you please provide a "SD driver for just Raw data transfers in asm" without FAT32 system, this would help many people who want to use simple storage of data on SD cards in their projects,especially those who code in AVR asm language - Thank you

Morgoth said...

The DelayWriteCommand and DelayReadCommand is used for wait until SD card is ready to accept data to be write on the card & ready to read data from the card, this delay is in bytes to ping the SD card, for example:
If i sent the read command , is necessarily to wait until the card is ready to read data, for this reason is necessary to ping the SD card with 255 integer until the card is responding with token, after this i get the 512 bytes from selected page,sending 512 bytes of 255 integer, this time is maximum to wait token from the SD card, in same cases SD card respond until 10 or more ping bytes.

Nischay,India said...

Hello Morgoth, Thanks for explaining in detail ! i have carefully gone thru your "sdDriver.asm" file,i just have few doubts:

1)during initializing SD card,other programmers recommend using slow SPI speed i,e about 400Khz and later switch to higher SPI speeds - but you have used fclk/4 speed for initializing & general working

2)Also,during init of SD card one has to send 74+ clocks but you are sending 20 idle bytes (subroutine: Sd_Idle_Bytes : Ldi R23,20)

3)".Equ ReadOnly = False" and
".if ReadOnly == False " should i remove these from the SdDriver.asm as i want to use only raw data.

Sorry,for bothering you so much, i know you would be busy with other projects but pl.i need your help

Morgoth said...

Response for (1):
400Khz is recommended but not necessary
Response for (2):
I now to send 74+ clocks but 74+, i used 160 clocks no problem.
Response for (3):
This "ReadOnly" is a constant and if is ".Equ ReadOnly = False" sd driver include and Write to card routines , if is ".Equ ReadOnly = True" Write routines is not included in library.

This constant is used for one program with write protected.

Nischay,India said...

Dear Morgoth, Thanks a lot for your support and time, will get back to you in case i run into problems :)

Nischay,India said...

Hello Morgoth,

sorry to bother you, iam having problem with reading the sectors with SdDriver.asm, iam able to write good amount of data(33MB) to sectors but unable to read from sectors. i have LED connected to a portpin which should glow if the card is initialized successfully and the LED should go off when read is complete, but the LED keeps "Blinking" (i,e ON & Off, i have disbaled 'WDR'in the driver file. please, need your help

Nischay,India said...

Hello Morgoth,

seems like you are very busy! can you please tell me what is the purpose of the following code in SdDriver.asm, (does it multiply sector address with 512??)

Mov R19,R18
Mov R18,R17
Mov R17,R16
Clr R16
Ldi R25,2

LoopTransformareaDinNumarulPaginiiInAdresaFizicaPeSd:
Cpi R25,1
Breq SaTerminatTransformareaDinNumarulPaginiiInAdresaFizicaPeSd
Clc
Rol R17
Rol R18
Rol R19
Lsr R25
Rjmp LoopTransformareaDinNumarulPaginiiInAdresaFizicaPeSd

Michael said...

Hello Morgoth,

I try to use your fat32 library in my project, but i've some problems. I can initialize SDdriver and write som date to the sdcard (folow your advice), but when i try to use Fat32DataLibraryInit command, the processor stops somewhere. Could you explain me, what should i do to read list of files from root directory and open some of them. Thanks.

Morgoth said...

Yes, is one problem in card initialization because the card initialization section is designed for new card design ( 512MB-1GB-2GB ).
The initialization is effectuated at maximum speed of the SPI ( Q freq/2 ).
For this reason is necessary to configure SPI prescaller to <400 Khz before initialization and to Q Freq/2 after initialization.

After initialization successful call this routines:

Call _Fat32DataLibrary+Fat32_GotoRoot
Call _Fat32DataLibrary+Fat32_ResetDirPointer

After you calling this routines the first file/folder short name can be read like this :
Call _Fat32DataLibrary+Fat32_GetShortFileName
And after you can get the short file name from here:
Z + ShortFilename

And the long file name:
Call _Fat32DataLibrary+Fat32_GetLongFileName And after you can get the short file name from here:

Z + LongFilename

For navigate in current folder call:

Call _fat32datalibrary+Fat32_incrementdirpointer
Call _fat32datalibrary+Fat32_decrementdirpointer

But for on entire project with this library please visit this link and you can get the source code:
http://digitalelectronicsandprograming.blogspot.com/2009/04/mp3-player-with-atmega64-vs1011a-and.html

Morgoth said...

Nischay,India

This code:

Mov R19,R18
Mov R18,R17
Mov R17,R16
Clr R16
Ldi R25,2

LoopTransformareaDinNumarulPaginiiInAdresaFizicaPeSd:
Cpi R25,1
Breq SaTerminatTransformareaDinNumarulPaginiiInAdresaFizicaPeSd
Clc
Rol R17
Rol R18
Rol R19
Lsr R25
Rjmp LoopTransformareaDinNumarulPaginiiInAdresaFizicaPeSd
SaTerminatTransformareaDinNumarulPaginiiInAdresaFizicaPeSd:


The multiplication is created in this mode for use for different page dimension,because this driver initially has been designed for variable card page dimension.

Michael said...

Thanks for help. Now I can read a list of files in any directory. I would be gratefull when you explain me how to read data from files. I can only read the first "sector" using instructions:
Fat32OpenPointedFileFolder
then read it from z+DataBufferOffset. I don't know how to read the rest of data.
Thanks for everything.
(I found some small mistake in Fat32ATmega64AsmLibraryReadOnly. In SDdriver library, in SdReadSector routine shouldn't be pop r20 instruction)

Morgoth said...

For reading data from a file after you call "Fat32OpenPointedFileFolder" the read write pointer is at offset 0 in file and you can read byte by byte with "Call _Fat32DataLibrary+Fat32_ReadByte" (the pointer ofset in file is autoincremented) and in Z+RegValueReadWrite you can read the byte, or one fast method : "Call Fat32OpenPointedFileFolder" read first sector data from buffer after this write in pointer offset:
Ldi R16,Low(512)
Ldi R17,Byte2(512)
Ldi R18,Byte2(512)
Ldi R19,Byte2(512)
Call _Fat32DataLibrary+Fat32_WritePointerInFile; For writing the offset in pointer inside file( write pointer to second sector)
Call _Fat32DataLibrary+Fat32_ReadByte; For reading the pointed ( second sector ) from sd card to buffer
Read 512 bytes from buffer that contain second sector from file
Ldi R16,Low(1024)
Ldi R17,Byte2(1024)
Ldi R18,Byte2(1024)
Ldi R19,Byte2(1024)
Call _Fat32DataLibrary+Fat32_WritePointerInFile; For writing the offset in pointer inside file( write pointer to third sector)
Call _Fat32DataLibrary+Fat32_ReadByte; For reading the pointed ( third sector ) from sd card to buffer
Read 512 bytes from buffer that contain third sector from file
etc

This method increase the speed to 8x in exchange for use only "Call _Fat32DataLibrary+Fat32_ReadByte" for reading byte by byte ( and not necessary to know what is in buffer and where is located the byte in buffer ) because "Call _Fat32DataLibrary+Fat32_ReadByte" calculate all for each byte read from sd.

For example with "Call _Fat32DataLibrary+Fat32_ReadByte" only i can play music at 320kb/s at 13Mhz and with last method i can play music at 320kb/s at 5Mhz.