Chan Fatfs

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

I just updated my Mega2561 test program with the latest Fatfs from Chan Ver. 0.08 and noticed an odd behavior. IF I do a:

di 0 = rc=0 ok
fi 0 = rc=0 ok
fl = rc=1 disk_err

I get an error on the first file operation no matter what type. After the first failure it always works fine afterward. It seems like something isn't getting initialized properly; anyone else experience this?

Thanks,
Mike

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

I found the problem. I had the SPI x2 still set but I had changed my crystal to 14.7456Mhz so I was trying to access the SD card at about 7 Mhz. Anyone know what the safest maximum speed is for most SD cards?

edit: Well it appears I didn't have my pullup enabled for MISO. After doing so it seems to run at full speed okay.

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

Quote:

Well it appears I didn't have my pullup enabled for MISO.

There are no pullups needed for SPI.

What you are probably seeing is the pullup helping to overcome line capacitance.

IIRC there is a fairly recent thread on max SD card SPI bit rate.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

I was not implying that SPI in general required pullups. Maybe some micro sd cards do though?

I had found several mentions of it during my searches so I checked and noticed I didn't have the internal pullup enabled so I tried it and it did the trick. I even tried another micro sd card that would never work even at very slow speeds and it worked perfect also at full speed.

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

Quote:
IIRC there is a fairly recent thread on max SD card SPI bit rate.

Do you by chance have a link to the discussion?

Btw, I did find a passage in the SD specifications that stated the host should provide suitable pullups on all data lines as outlined in section 6. Although I never found any more info in section 6?

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

Hmmmm--bet that ain't SPI mode.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
Hmmmm--bet that ain't SPI mode.

I found a little more info on the SanDisk website. Because of the different modes supported the data lines start out as "open drain" which is why they say that the SPI speed has to be under 400Khz during initializing. I'll have to do some tests. :)

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

Quote:

Do you by chance have a link to the discussion?

This is the one I was thinking of, perhaps:
https://www.avrfreaks.net/index.p...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Quote:

This is the one I was thinking of, perhaps:
https://www.avrfreaks.net/index.p... ... torder=asc

Thanks

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

Quote:
Anyone know what the safest maximum speed is for most SD cards?
I think I recall seeing a figure of 25mhz? somewhere.

I'm sure the real answer is 'it depends', but my guess is the avr will be hard pressed to outrun most sd cards, unless you are using an older card.

I am running a lpc1114 at an spi clock speed of 24mhz, which works ok on 2/4gb sd cards ('modern' cards).

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

I read in one of the data sheets that 25Mhz is the top for SPI this morning. From reading others experience thats seems about right. I already had a test setup that I knew worked at one time, but I had forgotten that I changed the crystal from 4Mhz to 14.7456 Mhz. So when I upgraded with Chans latest version I was running in circles a little :)
I was surprised to find that the AVR's weak pullup took it from flakey and not working to rock solid.

I'm guessing a lot of setups are going through some sort of voltage level schemes which probably adds a pullup so it's not noticed that often.
The cards I have are not that old really:

A-DATA 2G Micro SD - Doesn't work without Pullup
Kingston 1G Micro SD - Flakey without pullup

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

I've used 15-20 different SD and uSD cards with chanFat in SPI mode. 2/3 of them won't work without pullups at any speed. They all work with pullups. It does seem that talking SPI to SD cards can be a little tweaky, especially the 8GB+ HC cards.

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

I wonder if you can offer me some advice.
I am also getting disk_err when accessing the SD using Chan's fatfs.

I am using a Atmega128 running at 16mhz. VCC for the MCU is +5v so I am using a HFC4050B and a 3v3 regulator to convert the signals.

I added physical pullups to mosi, miso and CLK to stop any floating signals. I did use 47k which could be a mistake.

Another problem is the HFC4050B does not power on quickly enough to use the power on function but as I understand, id D0/1 are held low and 74 pulses at bellow 400khz should reset the SD into SPI mode.??

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

OK to answer my own question, this works:

Secondly SPI2X was enabled.

The only pullup needed was on D0

You need to be carefull of connecting a oscilloscope on the 3.3v logic side as it corrups data..

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

SPI spec may be 20+ MHz, but an SD card in SPI mode reaching anywhere near that speed is something I've NEVER seen ANYBODY do ( IIRC 20+ MHz SD card is only possible in SD mode ).

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

Having got past this, the next thing is to write a simple text file.

From Chan's doc, it says you can use f_open followed by f_lseek to move to the end of file.

The doc has this:
f_lseek(file, file->fsize);

But this does not compile, this does but give invalid_id_object:
f_lseek(&file, &file.fsize);

Any hints on what I am getting wrong?

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

flseek() is only used if you are appending. To simply create a file just fopen(), fwrite(), fclose().

Anyway, assuming you got your FatFs from ffsample.zip then look in avr/main.c and you will see an example of every API available. Searching for f_lseek() in that brings you to:

			case 'e' :	/* fe - Seek file pointer */
				if (!xatoi(&ptr, &p1)) break;
				res = f_lseek(&file1, p1);
				put_rc(res);
				if (res == FR_OK)
					xprintf(PSTR("fptr = lu(0x%lX)\n"), file1.fptr, file1.fptr);
				break;

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

Yes I should have been clear, I want to append text to a file a log of my ADC readings.
As I understand the example given, it moves to a specific pointer. That works no problem.
I wanted to move to end of file and write the next line with f_printf.

I am trying this:

res = f_open(&file1, "0:filename.txt", FA_CREATE_ALWAYS | RA_WRITE);
if (res) {
...
res = f_lseek(&file1, &file1->fsize);
...
res = f_printf(&file1, ...

file1->fsize is where I am lossing it :(

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

This is where a knowledge of POSIX filing on Windows or Linux comes into its own. In the PC world you use SEEK_END:

http://www.cplusplus.com/referen...

but failing that you can fstat the file to first find its size then seek to that point. fstat() is described:

http://pubs.opengroup.org/online...

As FatFs does not have the equivalent of SEEK_END then you need to use f_stat. Taking a look at the docs you find:

http://elm-chan.org/fsw/ff/en/st...

which fills a FILINFO structure:

http://elm-chan.org/fsw/ff/en/sf...

a field of which is:

    DWORD fsize;      /* File size */

so to seek to the end of a file for appending then first call f_stat() to fill a FILINFO structure then f_seek(&file1, info.fsize);

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

Quote:

res = f_lseek(&file1, &file1->fsize);

Quote:

file1->fsize is where I am lossing it

The second argument is not a pointer, but a 32-bit file position. You mentioned that earlier...
Quote:

The doc has this:
f_lseek(file, file->fsize);

But this does not compile,...


so tell more about that.

Look at the prototype:

FRESULT f_lseek (FIL*, DWORD);						/* Move file pointer of a file object */

Now, I do use an older "Tiny-FatFs - FAT file system module include file R0.06 (C)ChaN, 2008" but I don't think things have changed.

					// Put file pointer at end of file
					card_retval = f_lseek (&card_file_log, card_file_log.fsize);
					// Decide on actions to take if a failure
					if (card_retval != FR_OK)
						{...
						}

As mentioned, you don't need it for doing sequential writes. I have records in a "log file", and only use the lseek to get back to the end of the file after going back to my first "header record" and adding pieces of information about exceptions that occurred.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Thanks for the help, it really helps when you are tackling something new especially when it's both hardware and software.

I had tried

f_lseek(&file1, file1.fsize)

but must have had some other issue.
Will go back to that and try again.

Also now I see I should just open the file and keep writing to it and use f_sync to preserve data.

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

Quote:

use f_sync to preserve data

Yes, that is what I do. It isn't the fastest way, probably, doing a sync each time. But so far I've had good integrity with a simple (pretty much brute-force) approach.

-- Every one of my log records is 512 bytes, a full sector.
-- I write a header record when opening the log file. It has some useful information, such as app version, but it also kind of says "writing is working OK".
-- I f_sync() after each f_write().
-- Anytime I have a write failure, I simply close and "abandon" that file, and open the next. Power can cycle or card be removed at any instant, so perhaps that last record isn't completely valid. Start another "clean" one.
-- I start a new file each midnight as well.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Thanks theusch.

What I am doing is a energy monitor:

phase angles:

screen is still a bit debugy but you get the idea:)

I am now working on logging the output now.

Will need to work on 512 chunks but you have helped a lot thanks.

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

I have the luxury of it being a Mega640/Mega1280 app, so SRAM isn't as precious as e.g. a Mega88 app--full 512 byte sector buffers can be tolerated. Also, most of my logging records for a full completed "cycle" of my industrial app can be nearly that size.

It will depend on your app, and how critical any lost samples might be. Let's say you have 32 byte samples. You could write and sync each one. Or gather a number of samples and then do the full sector write. But then can you tolerate it if your app stops (loses power, card removed, whatever) and there are then lost samples sitting in SRAM that haven't been written? A tradeoff.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

OK implemented as said.
basically I do:
l_open
if the file size if > 0 do l_lseek
then I use l_puts to append to the file and l_sync to commit the data.
This runs every 3000 samples (10sec)
The sector size does not seem to be a problem.

So far I have 37k records in a 1.8mb file, so it looks ok.

The SD card can be removed and reinserted preserving the file and contents.

I am quite pleased with the results :)