[TUT] [C] Getting SD/MMC card working painlessly with FatFS

Go To Last Post
355 posts / 0 new

Pages

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

Lately, I've been trying to shift over to Eclipse (just to see how it is compared to AVR Studio v4) but when I import all the FatFS files and my main.c, I get the following error on every function declaration in xitoa.h

../xitoa.h:27:28: error: expected ';', ',' or ')' before '*' token

Here's an example function declaration in xitoa.h

void xputs(const prog_char *string);

Anybody have any idea what this could be? This isn't happening in AVR Studio v4 at all. I am able to compile and read/write to SD Cards.

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

It does not know what the typdef "prog_char" is. That actually comes from so it suggests that should be included above xitoa.h

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

is indeed included. I have not changed the files at all.

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

Then check the pgmspace.h in your system include path and ensure it contains:

typedef char prog_char PROGMEM;

What version of AVR-LibC are you using by the way? E.g.:

E:\WinAVR-20100110\avr\include\avr>grep __AVR_LIBC version.h
#define __AVR_LIBC_VERSION_STRING__ "1.6.7"
#define __AVR_LIBC_VERSION__        10607UL
#define __AVR_LIBC_DATE_STRING__    "20090702"
#define __AVR_LIBC_DATE_            20090702UL
#define __AVR_LIBC_MAJOR__          1
#define __AVR_LIBC_MINOR__          6
#define __AVR_LIBC_REVISION__       7

My WinAVR uses 1.6.7

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

You were right: pgmspace.h does not contain that definition. Does this imply my files are out-dated?

AVR-LibC version is 1.8.0. For what it's worth, I'm trying to use CrossPack-AVR on the Mac.

EDIT: SOrry, it does contain this:

typedef char prog_char __attribute__((__progmem__,deprecated("prog_char type is deprecated.")));
Last Edited: Tue. Feb 21, 2012 - 03:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

AVR-LibC version is 1.8.0. For what it's worth, I'm trying to use CrossPack-AVR on the Mac.

Then you are one of the first to be hit by this newly restructured PROGMEM support that looks like it's going to break a LOT oflegacy code. See the threads in GCC forum about GCC 4.7 and specifically those from SprinterSB to understand what's happening.

(this would now be more on-topic for one of those threads than this FatFs tutorial).

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

Hello

First off, thanks for a great guide. It helped me very much in getting the FatFS running! Good work!

I have a few questions that I hope you guys can help me with.

I get error 9(The file/directory object is invalid) when ever I use either f_puts or f_printf, some times the f_printf gives error 21, which I don't know what means.

FRESULT f_err_code;
static FATFS SD_Obj; 
error_code = disk_initialize(0);
f_err_code = f_mount(0, &SD_Obj);
f_err_code = f_open(&SDcard, "/loop.txt", FA_OPEN_ALWAYS | FA_WRITE);
f_err_code = f_lseek(&SDcard, f_size(&SDcard));
f_err_code = f_printf(&SDcard, " FORMAT_STRING " , "Get_fattime data: ", get_fattime(),"\r");
f_err_code = f_puts("***End_of_Header***",&SDcard);

for some reason I could not post the correct FORMAT_STRING in code, but it is: percent s, percent ld, percent s

The wierd thing is that all the text and numbers are printed to the file, so the functions are doing what they are supposed to. But why is the error not equal 0 then?

My second question:
In my project I need to sample two adc channels with 500-1000Hz, write the data to SD card and transfer the same data through zigbee (Atmega128RFA1). I know it might be impossible to save to sd and write to zigbee in less time then 1ms (1000hz sample rate) but none the less is this my end goal...
So I would like to create a buffer that fills one sector and flushes it to the SDcard (and possible to the zigbee as well).
I don't know how to do this, I am not quite sure if the FatFS contains a buffer system that I can use for this purpose?

Again thanks for a great guide and good support :)

Regards
Tommy

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

Quote:

I don't know how to do this, I am not quite sure if the FatFS contains a buffer system that I can use for this purpose?


Yes it already holds a sector buffer within the FATFS structure:

...
	BYTE	win[_MAX_SS];	/* Disk access window for Directory, FAT (and Data on tiny cfg) */
} FATFS;

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

Will it automatically flush the data when the buffer is full or should I do that manually?

I guess I could sample the adc, put the result into the buffer[i++] and when the buffer is full (i=511) flush the data (f_sync)?
I would like to write the two adc values countinuesly to a single file, so it will be easy to extract the data from the SDcard to excel/labview.

/Tommy

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

Quote:

Will it automatically flush the data when the buffer is full or should I do that manually?

It does it - that's the nature of the beast - it always holds the sector it's currently "working on" in that buffer.

I would not access the buffer directly to write to it (use the f_put/f_write/etc. functions to do that) but you may want read access if you want to send a copy to a different destination. You may even want to "hack" ff.c so it calls-back your own function each time before it discards the buffer.

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

Ahhh good idea with the "hacking", thanks clawson!

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

Hello, I have a project where I need to log data quickly to a SD/SDHC card. I don't plan on using a file system for now (I assume the overhead would make things slow down too much), and I believe I understand the SD card protocols well enough, but the actual specifications of the SD cards themselves are confusing me.

In short, many SD cards claim sustained write speeds of over 10MB/s, while in their documentation they will then say that it takes at least several milliseconds for a write operation to complete (I assume this refers to one block of 512 bytes). This seems to be a big contradiction, so I'm left unsure of what write speeds to expect from a given card. My goal is to get a sustained speed of at least 500KB/s, hopefully near 1MB/s. I've got a AT32UC3 with a 30MHz SPI and a couple DMA channels, and I've read that other people have achieved this with similar hardware (though some have not, and I assume the SD card itself is a big reason).

Does anyone here understand the SD card specs well enough to actually know what determines their write speeds (in SPI mode)? Does anyone have any recommendations of SD/SDHC card models which are known to get the write speeds I need?

Thanks in advance.

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

There's a difference between using these cards in SPI mode (which is compatible with MMC) and in the 4bit SD mode. For the latter you need to become a licensee of the SD association to gain access to the docs. (though a recent thread suggests that even MMC mode requires licensing). For typical MMC speeds see:

http://elm-chan.org/fsw/ff/img/r...

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

clawson wrote:
There's a difference between using these cards in SPI mode (which is compatible with MMC) and in the 4bit SD mode. For the latter you need to become a licensee of the SD association to gain access to the docs. (though a recent thread suggests that even MMC mode requires licensing).
Well I'm planning on using SPI mode, not the 4 bit SD mode.
Quote:
For typical MMC speeds see:

http://elm-chan.org/fsw/ff/img/r...

I think I've seen this same link come up in my previous searches, but it just redirects me to the homepage of yahoo.com.

My fundamental question is how can I look at the specifications of a card (I'm talking about the contents of its CSD register, not just its speed class or whatever) and use that to estimate what write speeds are attainable with SPI mode. Of course the SPI interface will degrade the attainable speed somewhat, but from what I've read the real bottleneck is usually in the SD card itself, specifically its program times.

If I can't get that answered, then I'd at least like to know of some card models which people have good experience with (and are capable of my desired speed).

Thanks!

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

I doubt the card's own write speed wil be the bootle-neck, it's how fast you can feed data to the card that will probably limit it (of course UC3 probably have more "oomph" in this sense than AVR).

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

I'd love to believe that the card won't be a bottleneck, but everything I've read by people who have actually used them says otherwise. Lots of people are using a 20MHz SPI clock with DMA control, but most people seem limited to a few hundred KB/s (while a few have been able to get speeds in excess of 1MB/s). I've read that the dominant bottleneck is just the time it takes for the card to go idle after a write is performed, so another write can begin.

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

A small question - I'm using FatFs on an SD Card and I also have 10 other devices on the SPI bus (all CPLDs). The very first thing that my program does is initialize the SD Card. I note that FatFs library contains the following macro.

Quote:
#define FCLK_FAST() SPCR = 0x50

which it calls after initialization succeeds. This equals about 2MHz on my AVR Mega 1281. But after the initialization, I setup SPI for my CPLDs - in this particular routine, I set my SPI speed to just 62.5KHz.

My question is, will the FatFs library now be operating at 62.5KHz? I don't think FCLK_FAST() is called anywhere else, so if I initialize the card the speed is set to 2MHz. I then call my function setupSPI() which sets the SPI speed to 62.5KHz. I then read from the SD Card and also read from the CPLDs. Unless the SPCR register is set again to 0x50, I don't think my SD Card is working at 2MHz. Am I correct?

I should add, the system is working very well. However, I have to extend the system to operate on a larger dataset - hence my concern about read/write speeds.

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

Quote:

My question is, will the FatFs library now be operating at 62.5KHz?

Yes.
Quote:

I don't think FCLK_FAST() is called anywhere else

I agree.

You could, I guess pepper FatFs with more calls to FCLK_FAST() (perhaps in the power_on routine?) and then setupSPI() when its deselected (power_off ?) or simply accept the 62.5kHz for SD access.

As with all optimizations I wouldn't actually bother until they actually become necessary - worry about this when you get to the point of believing that the file cannot be written quickly enough.

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

The ffsample.zip I downloaded from

http://elm-chan.org/fsw/ff/00ind...

doesn't seem consistent with this tutorial. For example:

Quote:
Continuing on, modify the #define SELECT() and #define DESELECT() as so:

There are no such lines in mmc.c--now they are functions:

static
void deselect (void)
{
	CS_HIGH();
	xchg_spi(0xFF);	/* Dummy clock (force DO hi-z for multiple slave SPI) */
}



/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready                                    */
/*-----------------------------------------------------------------------*/

static
int select (void)	/* 1:Successful, 0:Timeout */
{
	CS_LOW();
	xchg_spi(0xFF);	/* Dummy clock (force DO enabled) */

	if (wait_ready()) return 1;	/* OK */
	deselect();
	return 0;	/* Timeout */
}

I think I can still figure out what needs to be done, but is the older on which this tutorial was based still available? Or should I just use the newer version and expect only trivial differences?

Thanks!

Dave Thomas

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

As I ran into more or less the same thing that a lot has changed, I write here what things I changed in order to get FatFs version 0.09b to work.

you can download it from:
http://elm-chan.org/fsw/ff/00index_e.html
On the bottom of this page you can download the "FatFs sample projects"
This is a zip file with all the projects for a lot of different processors.
From this zip file I used the "avr" folder.
I used Atmel Studio 6.0(AS6)
I have a self made board with a Atmega1281 on it.

First step is to make a new project in AS6.
Copy the following files from the AVR folder to the project folder:
- cc932_avr.c (from unicode sub directory)
- diskio.h ,
- ff.c ,
- ff.h ,
- ffconf.h ,
- integer.h ,
- main.c ,
- mmc.c ,
- rtc.c ,
- rtc.h ,
- uart.c ,
- uart.h ,
- xitoa.h ,
- xitoa.s ,

Now I have made the following changes to the files to get them to work for me:

I made a board.h file that holds a number of board specific parameters. See file for details.

In the file "cc932_avr.c"
There are 4 references do the datatype "prog_uint16_t"
as this datatype is no longer supported int the atmel studio it must be changed.
from top to bottom thrue the file:

Quote:
const prog_uint16_t uni2sjis[] =
becomes:
const uint16_t uni2sjis[] PROGMEM =

const prog_uint16_t *p;
becomes:
const uint16_t *p;

static const prog_uint16_t tbl_lower[] =
becomes:
static const uint16_t tbl_lower[] PROGMEM=

static const prog_uint16_t tbl_upper[] =
becomes:
static const uint16_t tbl_upper[] PROGMEM=

In the file "ffconf.c"
I changed the following parameters:

Quote:
_USE_MKFS changed to 0
_USE_LABEL changed to 0
_USE_LFN changed to 1
_MAX_LFN changed to 20
_FS_RPATH changed to 0
_VOLUMES changed to 1

You have to check this file what options you want to use and what not.

In the files "uart.c & uart.h"
I changed all references from uart0 to uart1.
I removed:

	PORTE |= _BV(1); DDRE |= _BV(1);	/* Set TXD as output */
	DDRE &= ~_BV(0); PORTE &= ~_BV(0); 	/* Set RXD as input */

as this is already done during initialization.
I added:

void USART_set_baud_rate(uint32_t baudrate)
{
	// calculate division factor for requested baud rate, and set it
	int bauddiv = ((F_CPU+(baudrate*8L))/(baudrate*16L)-1);
	UBRR1L= bauddiv;
	#ifdef UBRR1H
	UBRR1H= (bauddiv>>8);
	#endif
}

and call that during uart initialization.

In the file "xitoa.h"
There are 4 references to "prog_char".
These all need to be replaced by "char"

The contents of the file rtc.c"
I do not have a RTC interface available. so I replaced the file contents with:

/*--------------------------------------------------------------------------*/ 
/*  RTC controls                                                            */ 

#include  
#include  
#include "rtc.h" 

int rtc_gettime (RTC *rtc) 
{ 
   //This code is just to provide some kind of a valid response. 
   rtc->sec = 1; 
   rtc->min = 2; 
   rtc->hour = 3; 
   rtc->mday = 4; 
   rtc->month = 5; 
   rtc->year = 2006; 


   return 1; 
} 

int rtc_settime (const RTC *rtc) 
{ 
   BYTE buf[8]; 

   buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10; 
   buf[1] = rtc->min / 10 * 16 + rtc->min % 10; 
   buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10; 
   buf[3] = 0; 
   buf[4] = rtc->mday / 10 * 16 + rtc->mday % 10; 
   buf[5] = rtc->month / 10 * 16 + rtc->month % 10; 
   buf[6] = (rtc->year - 2000) / 10 * 16 + (rtc->year - 2000) % 10; 

/*This is where you would set the new time to the clock*/ 

   return 1; 
} 

int rtc_init (void) 
{ 
/*This is where you would set-up your RTC device and read an initial datum*/
   return 1; 
} 

If you have a RTC available then you need to make that work here.

In the file "mmc.c"
You need to set the port controls to how your board is designed.

#define CS_LOW()	MMC_SEL_PORT &= ~(1<<MMC_SEL_LOC)      /* MMC CS = L */
#define	CS_HIGH()	MMC_SEL_PORT |=  (1<<MMC_SEL_LOC)		/* MMC CS = H */
#define SOCKINS		(!(MMC_PRES_PIN & (1<<MMC_PRES_LOC)))	/* Card detected.   yes:true(pin is low), no:false(pin is high), default:true */

As the MMC card does not have a write protection option the check on that alwasy ahs to return a false:

#define SOCKWP		0		/* Write protected. yes:true, no:false, default:false */

I also changed the fast and slow clock

#define	FCLK_SLOW()		SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(0<<SPR0)		/* Set slow clock (F_CPU / 32) */
#define	FCLK_FAST()		SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)					/* Set fast clock (F_CPU / 8) */

The functions "power_status, power_on and power_off" are replaced byt the following block:

static
int power_status (void)		/* Socket power state: 0=off, 1=on */
{
	return (MMC_PWR_PIN & ~(1<<MMC_PWR_LOC)) ? 0 : 1;	// if the power pin is high power is OFF
}

static
void power_on (void)
{
	MMC_PWR_PORT |= (1<< MMC_PWR_LOC);	// make power pin high to cut power
	CS_LOW();							// make chip select line also low to not power it through that

	for (Timer1 = 10; Timer1; );	/* Wait for 100ms */

	MMC_PWR_PORT &= ~(1<< MMC_PWR_LOC);	// make power pin low to apply power
	CS_HIGH();							// disable chip select

		//initialize the SPI bus;
	SPSR = (1<<SPI2X);	// speed = x2
	FCLK_SLOW();		
}

void power_off (void)
{
	Stat |= STA_NOINIT;      /* Set STA_NOINIT */
	MMC_PWR_PORT |= (1<< MMC_PWR_LOC);	// make power pin high to power off
	CS_LOW();            /* Wait for card ready */
}

In the file "main.c"
I removed the include for "sound.h" as I do not have sound available.
I also removed the "FUSES" definition as I use another processor and prefer to set those one time and set them myself.
As I use timer0 instead of timer2 I changed the interrupt vector for that and also the initialization in the "ioinit" function.

Also in this file a number of references to "prog_char" have to be changed to char + PROGMEM.

A new function is added for PIO Init. The original program does this in the ioinit function, you need to set these things correct for you specific design.

with these changes done you should be able to run the example project on your system.

I hope this will help others.

Attachment(s): 

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

Just to say that there are a couple of ways to approach this. In response to a thread here the other day I too downloaded 0.09b but rather than the generic:

http://elm-chan.org/fsw/ff/ff9b.zip

download link I think it's possibly easier to start with:

http://elm-chan.org/fsw/ff/ffsam...

which is linked as "FatFs sample projects" as this possibly starts closer to what you probably want to do than the generic file which, as meslomp's post shows, may require more work. Within the "Samples" archive is an AVR sub-folder that contains:

E:\ffavr\avr>dir /b
rtc.c
rtc.h
Makefile_mmcbb
mmc.c
ffconf.h
integer.h
sound.c
cfmm.c
diskio.h
Makefile_cfmm
uart.h
avr_ata.png
Makefile_cfc
uart.c
Makefile_mmc
main.c
ff.c
cfc.c
Makefile_ata
xitoa.S
ff.h
sound.h
avr_mmc.png
xitoa.h
avr_cfc.png
ata.c
mmcbb.c

That has support for building a number of targets but it's only the "mmc" variant that an AVR user will be interested in. So one can start by removing a majority of the files of no immediate relevance (personally I use a Subversion repository so I can easily get back anything that I modify or delete in error). Just retain the following files (in fact the uart.* are also optional):

mmc.c
ffconf.h
integer.h
diskio.h
uart.h
uart.c
ff.c
ff.h

Of these you shouldn't need to (indeed for library code you never should) edit the following:

ff.h
ff.c
diskio.h
integer.h

So the only files you may want to edit are:

1) mmc.c

Edit this to reflect your actual hardware wiring. In my case I changed:

#define CS_LOW()	PORTB &= ~1			/* CS=low */
#define	CS_HIGH()	PORTB |= 1			/* CS=high */
#define SOCKINS		(!(PINB & 0x10))	/* Card detected.   yes:true, no:false, default:true */
#define SOCKWP		(PINB & 0x20)		/* Write protected. yes:true, no:false, default:false */

to be:

#define SS		(1<<PB4)
#define MOSI	(1<<PB5)
#define MISO	(1<<PB6)
#define SCK		(1<<PB7)
#define CS_LOW()	PORTB &= ~SS			/* CS=low */
#define	CS_HIGH()	PORTB |= SS			/* CS=high */
#if 0 // not using
 #define SOCKINS		(!(PINB & 0x10))	/* Card detected.   yes:true, no:false, default:true */
 #define SOCKWP		(PINB & 0x20)		/* Write protected. yes:true, no:false, default:false */
#endif

and also:

static
int power_status (void)		/* Socket power state: 0=off, 1=on */
{
	return (PORTE & _BV(7)) ? 0 : 1;
}

to be:

static
int power_status (void)		/* Socket power state: 0=off, 1=on */
{
	return 1;
}

as my wiring did not include power control. Also:

static
void power_on (void)
{
	{	/* Remove this block if no socket power control */
		PORTE &= ~_BV(7);	/* Socket power on (PE7=low) */
		DDRE |= _BV(7);
		for (Timer1 = 2; Timer1; );	/* Wait for 20ms */
	}

	PORTB |= 0b00000101;	/* Configure SCK/MOSI/CS as output */
	DDRB  |= 0b00000111;

	SPCR = 0x52;			/* Enable SPI function in mode 0 */
	SPSR = 0x01;			/* SPI 2x mode */
}

static
void power_off (void)
{
	SPCR = 0;				/* Disable SPI function */

	DDRB  &= ~0b00110111;	/* Set SCK/MOSI/CS as hi-z, INS#/WP as pull-up */
	PORTB &= ~0b00000111;
	PORTB |=  0b00110000;

	{	/* Remove this block if no socket power control */
		PORTE |= _BV(7);		/* Socket power off (PE7=high) */
		for (Timer1 = 20; Timer1; );	/* Wait for 20ms */
	}
}

to be:

static
void power_on (void)
{

	PORTB |= SS | MOSI;	/* Configure SCK/MOSI/CS as output */
	DDRB  |= SS | SCK | MOSI;

	SPCR = 0x52;			/* Enable SPI function in mode 0 */
	SPSR = 0x01;			/* SPI 2x mode */
}

static
void power_off (void)
{
	SPCR = 0;				/* Disable SPI function */

	DDRB  &= ~(SS | SCK | MOSI);	/* Set SCK/MOSI/CS as hi-z, INS#/WP as pull-up */
	PORTB &= ~(SS | SCK | MOSI);
#if 0	// not using CP / WP
	PORTB |=  0b00110000;
#endif

}

That's because I wasn't using Card Present or Write Protect signals and I just think it's easier to document the setting of I/O bits using symbols rather than meaningless 0b101010111 style values.

The point here is that you edit mmc.c to reflect how you have things wired.

Note also that the 0.09b files have an error that Chan has inadvertently introduced. It's easiest to just add the #if/#endif to remove the whole thing:

#if 0
		case CTRL_ERASE_SECTOR :	/* Erase a block of sectors (used when _USE_ERASE == 1) */
			if (!(CardType & CT_SDC)) break;				/* Check if the card is SDC */
			if (disk_ioctl(drv, MMC_GET_CSD, csd)) break;	/* Get CSD */
			if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break;	/* Check if sector erase can be applied to the card */
			dp = buff; st = dp[0]; ed = dp[1];				/* Load sector block */
			if (!(CardType & CT_BLOCK)) {
				st *= 512; ed *= 512;
			}
			if (send_cmd(CMD32, st) == 0 && send_cmd(CMD33, ed) == 0 && send_cmd(CMD38, 0) == 0 && wait_ready(30000))	/* Erase sector block */
				res = RES_OK;	/* FatFs does not check result of this command */
			break;
#endif

2) ffconf.h

Everyone who uses FatFs is going to have different requirements. Personally I edited the following lines:

#define _FS_MINIMIZE	1	/* 0 to 3 */
#define	_USE_STRFUNC	1	/* 0:Disable or 1-2:Enable */
#define	_USE_MKFS		0	/* 0:Disable or 1:Enable */
#define _USE_LABEL		0	/* 0:Disable or 1:Enable */
#define _CODE_PAGE	1
#define _VOLUMES	1

Of those I think it's only the last two that almost everyone will probably edit. The _CODE_PAGE one to reduce reliance on international (probably Japanese) character sets and the _VOLUMES one as almost everyone using FatFs probably only has one SD/MMC card attached, not two.

3) something.c

You need to write some C code to actually do something with FatFs. The following is a very simply example that simply opens a file called "poem.txt" and outputs the lines of text that it contains:

#include 
#include 
#include "diskio.h"
#include "ff.h"
#include "uart.h"

FATFS fs;
FIL fin;

char line[80];
char sec[512];

int main(void)
{
	FRESULT res;
	OCR0 = 0xB3; // avrcalc says that at 3.6864MHz that /8 and CTC 0xB3 will give 10ms
	TIMSK = (1 << OCIE0); // use COMP interrupt
	TCCR0 = (1 << WGM01) | (1 << CS01); // CTC with div 8
	sei();
	if (disk_initialize(0) == STA_NOINIT) {
		while(1);
	}
	res = f_mount(0, &fs);
	if (res == FR_OK) {
		res = f_open(&fin, "poem.txt", FA_OPEN_EXISTING | FA_READ);
		if (res == FR_OK) {
			do {
				f_gets(line, sizeof(line), &fin);
				UART_puts(line);
				UART_put('\r');
			} while (!f_eof(&fin));
			f_close(&fin);
		}
	}		
    while(1)
    {
    }
}

ISR(TIMER0_COMP_vect) {
	disk_timerproc();
}

DWORD get_fattime (void)
{
	/* Pack date and time into a DWORD variable */
	return	  ((DWORD)(2013 - 1980) << 25)
	| ((DWORD)3 << 21)
	| ((DWORD)23 << 16)
	| ((DWORD)12 << 11)
	| ((DWORD)0 << 5)
	| ((DWORD)0 >> 1);
}

The two key things here that all FatFs programs will have are:

(a) you need to start a timer with a 10ms period and each time it expires call disk_timerproc()

(b) you need to provide the get_fattime() function that ff.c will call to time stamp files. If you don't have an RTC then just return a fixed date/time as shown here. You shouldn't need anything from any kind of rtc.h/rtc.c as this function alone is the only API that FatFs will attempt to call. In fact it could be even simpler - just return 0.

The AS6 project for all this is attached..

Attachment(s): 

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

Hi all.

I was wondering whether anybody was able to successfully run the ffsample (version 0.09b of FatFS) program for AVR and use the 'fr' and 'fd' commands.
It appears that the mem_cpy calls in f_read might be causing an MCU restart, possibly as these overwrite areas in RAM that they should not. I tried to run ffsample without other modifications than a simple port to ATMega644: in particular ffconf.h is as per zip provided by ChaN. The sequence of commands I tried was:
di 0
fi 0
fo 1 test.bin
fd 512
<- MCU restarts here

The same thing happens if I try the WAV playback command or data read one:

p file.wav
fr 512

If you had more luck than myself, I'd be grateful to know :)
Thank you!

SadicAVR

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

Clawson, Thank you. Thank you. Thank you.

(I'll not type it a thousand times.)

It worked second try. At first, it failed "no init." I checked lines, checked my pin definitions in mmc.c, checked with an ohm meter. Then thought, "This came from a phone, I wonder how it's formatted." So I formatted it fresh (2GB with 16KB blocks) and put my poem.txt and... WOW, it shows my parnassian attempt on the display!

274,207,281-1 The largest known Mersenne Prime

Measure twice, cry, go back to the hardware store

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

I am having lots of errors when I try to run the code after making these changes - functions like uart_putc and uart_getc are undefined, and variable type prog_char is not defined. Any ideas as to what I am doing wrong?

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

Well the uart functions aren't needed so remove anything that calls those. As for prog_char, that's deprecated in the latest compiler as it only ever worked by accident. Just use PROGMEM on char.

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

This is just an update of my post above to reflect that things have moved on a bit. I did the following using the Jun22 2013 copy of ffsample.zip from the FatFs site and the current issue of Studio 6 which is 6.1 with Service Pack 1.1 that is 6.1.2674

From ffsample.zip I just extracted the "avr" subdirectory and ignored everything else. This gave me:

E:\ffsamp-jun22\avr>dir
 Volume in drive E is VBOX_windows
 Volume Serial Number is 0000-0801

 Directory of E:\ffsamp-jun22\avr

09/06/2012  11:20             5,013 rtc.c
22/11/2011  21:24               573 rtc.h
23/03/2013  23:42             3,216 Makefile_mmcbb
22/06/2013  09:43            17,920 mmc.c
16/02/2013  11:58             7,632 ffconf.h
24/04/2010  23:45               856 integer.h
22/01/2013  00:58             7,408 sound.c
22/06/2013  09:43            30,708 cfmm.c
23/03/2013  23:20             2,890 diskio.h
16/02/2013  11:36             3,214 Makefile_cfmm
22/01/2013  00:58               349 uart.h
10/06/2012  19:44            13,551 avr_ata.png
16/02/2013  11:34             3,208 Makefile_cfc
22/01/2013  00:59             1,954 uart.c
23/03/2013  23:42             3,207 Makefile_mmc
22/06/2013  09:47            20,470 main.c
24/01/2013  00:06           147,958 ff.c
22/06/2013  09:44            14,404 cfc.c
16/02/2013  11:36             3,207 Makefile_ata
15/07/2012  19:36             9,905 xitoa.S
24/01/2013  00:06            13,063 ff.h
22/11/2011  22:26               562 sound.h
10/06/2012  19:44            12,037 avr_mmc.png
08/06/2011  22:17             3,086 xitoa.h
10/06/2012  19:44            13,579 avr_cfc.png
16/02/2013  12:28            14,237 ata.c
20/03/2013  21:26            16,376 mmcbb.c
11/07/2013  15:47              unicode

I added those to a local SVN so I could track changes and recover anything I delete or change in error.

As I'm only interested in SD/MMC using the SPI interface most of these files are not relevant so, like last time, I cut them down using svn-delete to be:

E:\ffsamp-jun22\avr>dir /o
 Volume in drive E is VBOX_windows
 Volume Serial Number is 0000-0801

 Directory of E:\ffsamp-jun22\avr

23/03/2013  23:20             2,890 diskio.h
24/01/2013  00:06           147,958 ff.c
24/01/2013  00:06            13,063 ff.h
16/02/2013  11:58             7,632 ffconf.h
24/04/2010  23:45               856 integer.h
22/06/2013  09:47            20,470 main.c
23/03/2013  23:42             3,207 Makefile_mmc
22/06/2013  09:43            17,920 mmc.c
22/01/2013  00:59             1,954 uart.c
22/01/2013  00:58               349 uart.h
08/06/2011  22:17             3,086 xitoa.h
15/07/2012  19:36             9,905 xitoa.S

That's still too many files as I don't really intend to use the Makefile and I'm not sure about the uart.* files but I'll cut things down further later.

Next I wanted to make this into an AS6 project. Unfortunately AS6 has a habit of creating things you don't actually want and won't create a project within a directory that already exists when you create a new project but undeterred I told it to create a new GCC C project.

Now I wanted it to use the \ffsamp-jun22\avr directory where I already had files so I pointed "Location:" to the ffsamp-jun22 directory and asked for the project to be called "FatfsAVR" and un-ticked the "Create directory for project" button. I arbitrarily chose to make the project for atmega32 as that's what I happened to have plugged into my STK500 with SD/MMC socket attached. This created a file called FatfsAVR.c in \ffsamp-jun22\FatfsAVR\ directory so at this stage my tree of files looked like this:

E:\ffsamp-jun22>tree /f
Folder PATH listing for volume VBOX_windows
Volume serial number is 00070000 0000:0801
E:.
├───FatfsAVR
│   │   FatfsAVR.cproj
│   │   FatfsAVR.c
│   │   FatfsAVR.atsuo
│   │   FatfsAVR.atsln
│   │
│   └───Debug
└───avr
        mmc.c
        ffconf.h
        integer.h
        diskio.h
        uart.h
        uart.c
        Makefile_mmc
        main.c
        ff.c
        xitoa.S
        ff.h
        xitoa.h

My plan here is not to use the FatFs supplied main.c but, instead, put a small driving test program into the FatfsAVR.c file that AS6 just created.

So next I need to make AS6 aware of the files I want compiled into the project. In the Solution Explorer I right-click the FatfsAVR project and from the Context menu use "Add" and within that "Existing item...". I then select "ff.c", "mmc.c", "uart.c" and "xitoa.S" using the "Add as link" option on the dialog's add button (don't just use [Add] or those files will be copied from the "avr" subdirectory" to the "FatfsAVR" directory.

If I try to build at this stage I get errors about PORTE being used in mmc.c. This is because the Chan supplied code is intended for a mega64 and I am building for a mega32. So, just as in my previous post, I will make some modifications to mmc.c. In Chan's code where PORTE is used he has comments such as:

	{	/* Remove this block if no socket power control */
		PORTE &= ~_BV(7);	/* Socket power on (PE7=low) */
		DDRE |= _BV(7);
		for (Timer1 = 2; Timer1; );	/* Wait for 20ms */
	}

As I'm not going to use socket power control I will follow this advice and remove anything that makes access to PORTE. I also modify power_status() so it always returns 1. And I apply changes as shown in my previous message to configure things for the SPI pins on mega32. SVN tells me that what I changed was:

Index: mmc.c
===================================================================
--- mmc.c	(revision 14)
+++ mmc.c	(working copy)
@@ -7,8 +7,13 @@
 
 
 /* Port controls  (Platform dependent) */
-#define CS_LOW()	PORTB &= ~1			/* CS=low */
-#define	CS_HIGH()	PORTB |= 1			/* CS=high */
+#define SS      (1<<PB4)
+#define MOSI   (1<<PB5)
+#define MISO   (1<<PB6)
+#define SCK      (1<<PB7)
+
+#define CS_LOW()	PORTB &= ~SS			/* CS=low */
+#define	CS_HIGH()	PORTB |= SS			/* CS=high */
 #define SOCKINS		(!(PINB & 0x10))	/* Card detected.   yes:true, no:false, default:true */
 #define SOCKWP		(PINB & 0x20)		/* Write protected. yes:true, no:false, default:false */
 #define	FCLK_SLOW()	SPCR = 0x52		/* Set slow clock (F_CPU / 64) */
@@ -63,21 +68,15 @@
 static
 int power_status (void)		/* Socket power state: 0=off, 1=on */
 {
-	return (PORTE & _BV(7)) ? 0 : 1;
+	return 1;
 }
 
 static
 void power_on (void)
 {
-	{	/* Remove this block if no socket power control */
-		PORTE &= ~_BV(7);	/* Socket power on (PE7=low) */
-		DDRE |= _BV(7);
-		for (Timer1 = 2; Timer1; );	/* Wait for 20ms */
-	}
+   PORTB |= SS | MOSI;		/* Configure SCK/MOSI/CS as output */
+   DDRB  |= SS | SCK | MOSI;
 
-	PORTB |= 0b00000101;	/* Configure SCK/MOSI/CS as output */
-	DDRB  |= 0b00000111;
-
 	SPCR = 0x52;			/* Enable SPI function in mode 0 */
 	SPSR = 0x01;			/* SPI 2x mode */
 }
@@ -87,14 +86,8 @@
 {
 	SPCR = 0;				/* Disable SPI function */
 
-	DDRB  &= ~0b00110111;	/* Set SCK/MOSI/CS as hi-z, INS#/WP as pull-up */
-	PORTB &= ~0b00000111;
-	PORTB |=  0b00110000;
-
-	{	/* Remove this block if no socket power control */
-		PORTE |= _BV(7);		/* Socket power off (PE7=high) */
-		for (Timer1 = 20; Timer1; );	/* Wait for 20ms */
-	}
+   DDRB  &= ~(SS | SCK | MOSI);   /* Set SCK/MOSI/CS as hi-z, INS#/WP as pull-up */
+   PORTB &= ~(SS | SCK | MOSI);
 }

Having cleared errors in mmc.c I then get errors in uart.c. I figure it is worth making it work for mega32 so I modify it as follows (also adding a definition of F_CPU=3686400 to the project symbols):

Index: uart.c
===================================================================
--- uart.c	(revision 14)
+++ uart.c	(working copy)
@@ -24,16 +24,13 @@
 
 void uart_init (uint32_t bps)
 {
-	UCSR0B = 0;
+	UCSRB = 0;
 
-	PORTE |= _BV(1); DDRE |= _BV(1);	/* Set TXD as output */
-	DDRE &= ~_BV(0); PORTE &= ~_BV(0); 	/* Set RXD as input */
-
 	RxFifo.ct = 0; RxFifo.ri = 0; RxFifo.wi = 0;
 	TxFifo.ct = 0; TxFifo.ri = 0; TxFifo.wi = 0;
 
-	UBRR0L = F_CPU / bps / 16 - 1;
-	UCSR0B = _BV(RXEN0) | _BV(RXCIE0) | _BV(TXEN0);
+	UBRRL = F_CPU / bps / 16 - 1;
+	UCSRB = _BV(RXEN) | _BV(RXCIE) | _BV(TXEN);
 }
 
 
@@ -76,7 +73,7 @@
 	TxFifo.buff[i] = d;
 	cli();
 	TxFifo.ct++;
-	UCSR0B = _BV(RXEN0) | _BV(RXCIE0) | _BV(TXEN0) | _BV(UDRIE0);
+	UCSRB = _BV(RXEN) | _BV(RXCIE) | _BV(TXEN) | _BV(UDRIE);
 	sei();
 	TxFifo.wi = (i + 1) % sizeof TxFifo.buff;
 }
@@ -84,12 +81,12 @@
 
 /* UART RXC interrupt */
 
-ISR(USART0_RX_vect)
+ISR(USART_RXC_vect)
 {
 	uint8_t d, n, i;
 
 
-	d = UDR0;
+	d = UDR;
 	n = RxFifo.ct;
 	if (n < sizeof RxFifo.buff) {
 		RxFifo.ct = ++n;
@@ -102,7 +99,7 @@
 
 /* UART UDRE interrupt */
 
-ISR(USART0_UDRE_vect)
+ISR(USART_UDRE_vect)
 {
 	uint8_t n, i;
 
@@ -111,9 +108,9 @@
 	if (n) {
 		TxFifo.ct = --n;
 		i = TxFifo.ri;
-		UDR0 = TxFifo.buff[i];
+		UDR = TxFifo.buff[i];
 		TxFifo.ri = (i + 1) % sizeof TxFifo.buff;
 	}
-	if (n == 0) UCSR0B = _BV(RXEN0) | _BV(RXCIE0) | _BV(TXEN0);
+	if (n == 0) UCSRB = _BV(RXEN) | _BV(RXCIE) | _BV(TXEN);
 }

At this stage the project now builds without error. However there is nothing in main() actually calling any FatFs function and ffconf.h needs to be edited. If I turn off Linker garbage collection the project builds to :

	Program Memory Usage 	:	21350 bytes   65.2 % Full
	Data Memory Usage 	:	280 bytes   13.7 % Full

After making the following edits to ffconf.h:

Index: ffconf.h
===================================================================
--- ffconf.h	(revision 14)
+++ ffconf.h	(working copy)
@@ -26,7 +26,7 @@
 /  f_truncate and useless f_getfree. */
 
 
-#define _FS_MINIMIZE	0	/* 0 to 3 */
+#define _FS_MINIMIZE	1	/* 0 to 3 */
 /* The _FS_MINIMIZE option defines minimization level to remove some functions.
 /
 /   0: Full function.
@@ -36,11 +36,11 @@
 /   3: f_lseek is removed in addition to 2. */
 
 
-#define	_USE_STRFUNC	0	/* 0:Disable or 1-2:Enable */
+#define	_USE_STRFUNC	1	/* 0:Disable or 1-2:Enable */
 /* To enable string functions, set _USE_STRFUNC to 1 or 2. */
 
 
-#define	_USE_MKFS		1	/* 0:Disable or 1:Enable */
+#define	_USE_MKFS		0	/* 0:Disable or 1:Enable */
 /* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
 
 
@@ -48,7 +48,7 @@
 /* To enable fast seek feature, set _USE_FASTSEEK to 1. */
 
 
-#define _USE_LABEL		1	/* 0:Disable or 1:Enable */
+#define _USE_LABEL		0	/* 0:Disable or 1:Enable */
 /* To enable volume label functions, set _USE_LAVEL to 1 */
 
 
@@ -60,7 +60,7 @@
 / Locale and Namespace Configurations
 /----------------------------------------------------------------------------*/
 
-#define _CODE_PAGE	932
+#define _CODE_PAGE	1
 /* The _CODE_PAGE specifies the OEM code page to be used on the target system.
 /  Incorrect setting of the code page can cause a file open failure.
 /
@@ -127,7 +127,7 @@
 / Physical Drive Configurations
 /----------------------------------------------------------------------------*/
 
-#define _VOLUMES	2
+#define _VOLUMES	1
 /* Number of volumes (logical drives) to be used. */

that changes to be:

	Program Memory Usage 	:	16232 bytes   49.5 % Full
	Data Memory Usage 	:	166 bytes   8.1 % Full

Now I just need some code in the main() function. I edited FatfsAVR.c to be very like the main file from the previous thread, that is:

/*
 * FatfsAVR.c
 *
 * Created: 11/07/2013 16:16:42
 *  Author: cliff
 */ 

#include 
#include 
#include "../avr/diskio.h"
#include "../avr/ff.h"
#include "../avr/uart.h"

void uart_puts(char * str);

FATFS fs;
FIL fin;

char line[80];
char sec[512];

int main(void)
{
	FRESULT res;
	OCR0 = 0xB3; // avrcalc says that at 3.6864MHz that /8 and CTC 0xB3 will give 10ms
	TIMSK = (1 << OCIE0); // use COMP interrupt
	TCCR0 = (1 << WGM01) | (1 << CS01); // CTC with div 8
	sei();
	if (disk_initialize(0) == STA_NOINIT) {
		while(1);
	}
	res = f_mount(0, &fs);
	if (res == FR_OK) {
		res = f_open(&fin, "poem.txt", FA_OPEN_EXISTING | FA_READ);
		if (res == FR_OK) {
			do {
				f_gets(line, sizeof(line), &fin);
				uart_puts(line);
				uart_putc('\r');
			} while (!f_eof(&fin));
			f_close(&fin);
		}
	}
	while(1)
	{
	}
}

ISR(TIMER0_COMP_vect) {
	disk_timerproc();
}

void uart_puts(char * str) {
	while (*str) {
		uart_putc(*str++);
	}
}

DWORD get_fattime (void)
{
	/* Pack date and time into a DWORD variable */
	return     ((DWORD)(2013 - 1980) << 25)
	| ((DWORD)3 << 21)
	| ((DWORD)23 << 16)
	| ((DWORD)12 << 11)
	| ((DWORD)0 << 5)
	| ((DWORD)0 >> 1);
}

I switched garbage collection back on so the link would only include the functions that were called and this gave a final:

	Program Memory Usage 	:	11086 bytes   33.8 % Full
	Data Memory Usage 	:	1364 bytes   66.6 % Full

I've still got to actually test this but that looks pretty reasonable. The full project dir I used is zipped and attached.

Attachment(s): 

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

I've now tested that and it works but I did have to make this following change that I had forgotten above (because I don't use the card inserted and write protect signals):

Index: mmc.c
===================================================================
--- mmc.c	(revision 15)
+++ mmc.c	(working copy)
@@ -14,8 +14,10 @@
 
 #define CS_LOW()	PORTB &= ~SS			/* CS=low */
 #define	CS_HIGH()	PORTB |= SS			/* CS=high */
-#define SOCKINS		(!(PINB & 0x10))	/* Card detected.   yes:true, no:false, default:true */
-#define SOCKWP		(PINB & 0x20)		/* Write protected. yes:true, no:false, default:false */
+#if 0
+	#define SOCKINS		(!(PINB & 0x10))	/* Card detected.   yes:true, no:false, default:true */
+	#define SOCKWP		(PINB & 0x20)		/* Write protected. yes:true, no:false, default:false */
+#endif
 #define	FCLK_SLOW()	SPCR = 0x52		/* Set slow clock (F_CPU / 64) */
 #define	FCLK_FAST()	SPCR = 0x50		/* Set fast clock (F_CPU / 2) */
 
@@ -589,6 +591,7 @@
 
 	s = Stat;
 
+#if 0
 	if (SOCKWP)				/* Write protected */
 		s |= STA_PROTECT;
 	else					/* Write enabled */
@@ -598,6 +601,7 @@
 		s &= ~STA_NODISK;
 	else					/* Socket empty */
 		s |= (STA_NODISK | STA_NOINIT);
+#endif		
 
 	Stat = s;				/* Update MMC status */
 }

Also I modified main() with more uart stuff and remembered to initialize it...

int main(void)
{
	FRESULT res;
	OCR0 = 0xB3; // avrcalc says that at 3.6864MHz that /8 and CTC 0xB3 will give 10ms
	TIMSK = (1 << OCIE0); // use COMP interrupt
	TCCR0 = (1 << WGM01) | (1 << CS01); // CTC with div 8
	sei();
	uart_init(115200);
	uart_puts("Hello world\r\n");
	res = disk_initialize(0);
	if (res == STA_NOINIT) {
		uart_puts("no init\n");
		while(1);
	}
	res = f_mount(0, &fs);
	if (res == FR_OK) {
		res = f_open(&fin, "poem.txt", FA_OPEN_EXISTING | FA_READ);
		if (res == FR_OK) {
			do {
				f_gets(line, sizeof(line), &fin);
				uart_puts(line);
				uart_putc('\r');
			} while (!f_eof(&fin));
			f_close(&fin);
		}
		else {
			uart_puts("open error = ");
			uart_putc(res + '0');
			uart_puts("\r\n");
		}
	}
	else {
		uart_puts("can't mount");
	}
	while(1)
	{
	}
}

With all that I saw...

Attachment(s): 

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

clawson wrote:

OCR0 = 0xB3; // avrcalc says that at 3.6864MHz that /8 and CTC 0xB3 will give 10ms

Probably not fundamental, but I thought to mention this. With a divider of just 8 and a 3.6864 MHz clock, an 8-bit compare value is not enough to trigger a compare interrupt every 10ms.

Shouldn't the prescaler be 256 and OCR0 preloaded with 0x8F?

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

@clawson: can you please try the f_read function after opening a file for read? It wouldn't have to do anything complex, just read a few bytes and show them:

BYTE buff[5], i;
UINT br;

...
res = f_open(&fin, "poem.txt", FA_OPEN_EXISTING | FA_READ);

if (res == FR_OK) {
  res = f_read (&fin, (void *)buff, 5, &br);

  if (res == FR_OK)
    for (i = 0; i < br; i++)
      uart_putc (buff[i]);

  f_close (&fin);
}

Does it work for you?

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

sadicavr wrote:
@clawson: can you please try the f_read function after opening a file for read?

It appears that I am using a toolchain for which your project does not work. As it's an old toolchain from a few years back (Win AVR), I will try to update that first and then retry.

Edit: yes, even ChaN's example works now that I moved to the latest AVR toolchain.

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

i am getting the following errors with function wait_ready()

Error 4 static declaration of 'wait_ready' follows non-static declaration

Error 5 previous implicit declaration of 'wait_ready' was here

any ideas?

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

Have you edited the files? If I grep for wait_ready in recent FatFs files all I find is:

E:\ffsamp-jun22\avr>grep wait_ready *
mmc.c:int wait_ready (  /* 1:Ready, 0:Timeout */
mmc.c:  if (wait_ready(500)) return 1;  /* OK */
mmc.c:  if (!wait_ready(500)) return 0;

no mention of "static" in any of that.

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

I get this error after i replace the power_off function with the one author gave i.e

static
void power_off (void)
{
   SELECT();            /* Wait for card ready */
   wait_ready();
   release_spi();
   Stat |= STA_NOINIT;      /* Set STA_NOINIT */
} 

This function has wait_ready..

well the samples.zip i downloaded seems to have a bit different code. e.g in this tutorial author said to comment the lines from PORTA to PORTG in main.c The code in your file (even though it is commented but for the sake of comparison) is different from what i have. Notice the values of Ports are different in the file i have.

static
void ioinit (void)
{
	/* Pull-up all GPIO pins */
 	PORTA = 0b11111111; // These values are different
 	PORTB = 0b11111111;
 	PORTC = 0b11111111;
 	PORTD = 0b11111111;
 	PORTE = 0b11111111;
 	PORTF = 0b11111111;
 	PORTG = 0b00011111;

	/* Start 100Hz system timer (TC2.OC) */
	OCR2 = F_CPU / 1024 / 100 - 1;
	TCCR2 = 0b00001101;
	TIMSK |= _BV(OCIE2);
               // No rtc_init(); here <<
	sei();
}

next he mentioned to modify the #define SELECT() and #define DESELECT() but in my mmc.c There are no such defines... i have two functions for select and deselect though

static
void deselect (void)
{
	CS_HIGH();
	xchg_spi(0xFF);	/* Dummy clock (force DO hi-z for multiple slave SPI) */
}



/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready                                    */
/*-----------------------------------------------------------------------*/

static
int select (void)	/* 1:Successful, 0:Timeout */
{
	CS_LOW();
	xchg_spi(0xFF);	/* Dummy clock (force DO enabled) */

	if (wait_ready(500)) return 1;	/* OK */
	deselect();
	return 0;	/* Timeout */
}

Then it has SOCKWP and SOCKINS defines but no SOCKPORT. Also there is no such function chk_power(void) in my file. Are the files in avr directory updated/changed?

Edit: my AVR studio 5 does not seems to be detecting BOOL in rtc functions i.e:
BOOL rtc_settime (const RTC *rtc)

It says: Error 1 expected '=', ',', ';', 'asm' or '__attribute__' before 'rtc_gettime'

and using the replaced uart code it says: too many arguments to function 'uart_init'

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

Quote:

this tutorial author said

Are you talking about page 1? You are only ready to start when you have read through ALL fifteen pages as there have been many updates as Chan has changed his code over the years.

For example I made this update post on Jul 11 this year using Chan's code from Jun 22nd this year:

http://www.avrfreaks.net/index.p...

If you have just downloaded ffsample.zip I doubt that it is very different from that and my instructions there should work.

But do read all fifteen pages as there may be other interesting facts you need to know about.

EDIT: I have now edited a note into the first post to warn other users that it is not contemporary.

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

clawson wrote:
Quote:

this tutorial author said

Are you talking about page 1? You are only ready to start when you have read through ALL fifteen pages as there have been many updates as Chan has changed his code over the years.

For example I made this update post on Jul 11 this year using Chan's code from Jun 22nd this year:

http://www.avrfreaks.net/index.p...

If you have just downloaded ffsample.zip I doubt that it is very different from that and my instructions there should work.

But do read all fifteen pages as there may be other interesting facts you need to know about.

EDIT: I have now edited a note into the first post to warn other users that it is not contemporary.

yes i figured that out earlier and am already on 4th page. Actually am learning and until now i know how to send commands to SD card such as initialize read write, but i am having problems reading or writing the data sent to/by the card. And then i have to do all this using FAT32 so m quite getting lost in it.
Is interfacing SD card that hard and time consuming or am i the only one not getting the proper way to do it?

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

There are two levels at which you can use an SD/MMC card. You can just use it like a memory chip that has 512 byte pages. So you can say "write these 512 bytes to page 12345" and later "give me back the contents of page 12345". That's fine but does not allow you to use "files". So you cannot say "give me the 10 bytes at offset 1000 in a file called \data\mydata.txt". If you want that kind of access then you need FAT. FAT is not something you can write on your own (well not without about a year to spare). Thankfully E L Chan has done 95% of the work for us so we only have to fill in the last 5% (he doesn't know our file is called mydata.txt and that it's in the \data directory so we have to supply those details)

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

Hello again,
in a post you wrote that you were able to run the Petit FATFS right out-of-the-box but i am having problems.. it keeps giving me following errors:

-undefined reference to `xputs'
-undefined reference to `xputc'
-undefined reference to `xprintf'
-undefined reference to `xmit_spi'
-undefined reference to `xitoa'
-undefined reference to `rcv_spi'

and many more undefined errors. Well these are important functions and i cant simply remove them and also i am unable to modify it since the suart, usi and xitoa are assembler files (which is quite weird for me since we are coding in C)

i have added all the files in project directory as seen in attached picture.
Also there are couple of errors in these .S files as well e.g:
Error 2 number must be positive and less than 64

How did it work for you right away?

Using the petitFATfs was just an alternative, if doesn't work out ill modify the main FATfs according to your previous posts.

Attachment(s): 

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

Quote:

it keeps giving me following errors:

So you need to work out where those functions are located:

E:\pfsample\avr>grep xputs *
main.c: xputs(PSTR("  "));
main.c: xputs(PSTR("\nPFF test monitor\n"));
main.c:                         xputs(PSTR("Enter lines to write. A blank line finalize the write operation.\n"));
xitoa.S:;Prototype: void xputs (const prog_char *str // rom string to be output
xitoa.S:.global xputs
xitoa.S:.func xputs
xitoa.S:xputs:
xitoa.S:        rcall   xputs
xitoa.h:void xputs(const prog_char *string);

So clearly those functions are in xitoa.S. I'd therefore suggest that when you built the code and got those "undefined reference" errors you did not have xitoa.S listed as a component of the project.

Rather curiously, though, the picture you posted does show that (and other .S) to be present so are you really saying that you still got the error when building the project showin in the picture? I doubt it.

Quote:

(which is quite weird for me since we are coding in C)

Why is it unusual to have a project that mixes C and Asm? When you think about it all the C you write is going to be converted to Asm before it is assembled anyway.
Quote:
How did it work for you right away?

If I unpack the files and simply type the command "make" in the directory where they are located his happens:

E:\pfsample\avr>make
avr-gcc -gdwarf-2 -Wall -Os -mcall-prologues -mmcu=attiny85 -DF_CPU=8000000   -c -o main.o main.c
avr-gcc -gdwarf-2 -Wall -Os -mcall-prologues -mmcu=attiny85 -DF_CPU=8000000   -c -o pff.o pff.c
avr-gcc -gdwarf-2 -Wall -Os -mcall-prologues -mmcu=attiny85 -DF_CPU=8000000   -c -o mmc.o mmc.c
avr-gcc -c -mmcu=attiny85 -I. -x assembler-with-cpp -Wa,-adhlns=suart.lst,-gstabs -DF_CPU=8000000 suart.S -o suart.o
avr-gcc -c -mmcu=attiny85 -I. -x assembler-with-cpp -Wa,-adhlns=xitoa.lst,-gstabs -DF_CPU=8000000 xitoa.S -o xitoa.o
avr-gcc -c -mmcu=attiny85 -I. -x assembler-with-cpp -Wa,-adhlns=usi.lst,-gstabs -DF_CPU=8000000 usi.S -o usi.o
avr-gcc -gdwarf-2 -Wall -Os -mcall-prologues -mmcu=attiny85 -DF_CPU=8000000 -Wl,-Map,pfftest.map -o pfftest.elf main.o p
ff.o mmc.o suart.o xitoa.o usi.o
avr-objdump -h -S pfftest.elf > pfftest.lst
avr-objcopy -j .text -j .data -O ihex pfftest.elf pfftest.hex
avr-size -C --mcu=attiny85 pfftest.elf
AVR Memory Usage
----------------
Device: attiny85

Program:    8066 bytes (98.5% Full)
(.text + .data + .bootloader)

Data:        139 bytes (27.1% Full)
(.data + .bss + .noinit)

That certainly looks like it works straight out of the box to me!

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

sorry for being ignorant, where do you type make?
I am using avr studio 5 and use the button " Build Solution" normally.

Well i simply added all the files to the project folder and here is an error in usi.S file (i know after fixing it there will be more)

Line:> ldi r24, lo8(F_CPU / 100000) /* Loop counter */
Error:> undefined symbol `F_CPU' in operation

i have however defined it in main function as
#define F_CPU 16000000UL

If i conver it to ldi r24, lo8(160) /* Loop counter */
i get: Error 7 region `text' overflowed by 266 bytes

Also there is an error regarding DRESULT disk_readp being defined in both mmc.c and diskio.c Should i delete one? Kindly note only names are the same, the code inside functions is different.

I am sorry if my questions seem annoying to you since i am somewhat new to using libraries and this SD card interface is something which i am not getting used to at all

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

Quote:

i have however defined it in main function as
#define F_CPU 16000000UL

That won't be seen when the assembler works with usi.S. Put the definition of F_CPU in your project options (and remove it from your "main function").

Quote:
sorry for being ignorant, where do you type make?

On a command prompt, with the current directory being "the directory where [the unpacked files] are located".

I am using avr studio 5 [...] 

This has little or nothing to do with your current problems, but please note that AVR Studio 5 was not one of Atmels greatest moments. It had several bugs, and was quickly superseded by Atmel Studio 6. My advice to you is to upgrade to AS6.1 SP1 in the near future.

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Mon. Aug 5, 2013 - 01:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

by the way build succeeded with slight modifications to your code/instructions given in page 15. Soon gonna test it out but first i must study it

and yes the instructions given by you is way simple and easily understandable. Thankyou for your time and effort

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

JohanEkdahl wrote:
Quote:

i have however defined it in main function as
#define F_CPU 16000000UL

That won't be seen when the assembler works with usi.S. Put the definition of F_CPU in your project options (and remove it from your "main function").

Quote:
sorry for being ignorant, where do you type make?

On a command prompt, with the current directory being "the directory where [the unpacked files] are located".

I am using avr studio 5 [...] 

This has little or nothing to do with your current problems, but please note that AVR Studio 5 was not one of Atmels greatest moments. It had several bugs, and was quickly superseded by Atmel Studio 6. My advice to you is to upgrade to AS6.1 SP1 in the near future.

Sure will. I typed it in command prompt and this is what i got..

>make
Command "make" is not valid.

I am sure it has to do with my current directory, how do i set that? Also shouldn't it already be set to the current project?

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

Quote:

I am using avr studio 5

Your joking? I thought everyone knew about version 5 at this stage - it's been more than 2 years? The only "safe" version of Studio to use is the latest one. That is 6.1 wit SP1.1 which brings it to 6.1.2674. If you use an older version and especially if you are mad enough to still be using AS5 then replace it immediately.
Quote:

sorry for being ignorant, where do you type make?

At a "Command Prompt". This is the way programmers have built code for 30-40 years, long before fancy GUIs and IDEs like Windows and AS6 existed. In the pfsample.zip files there is a special one called "Makefile". If you switch to the directory where that is located and type "make" (and the GNU make.exe program is in your PATH) then it will read the Makefile and use it as a "recipe" to know how to compile and link and otherwise generate the code image. As you can see above that involved it passing a number of .c files to the linker to be compiled into .o files (-c). The .S files were passed to the assembler and it also generated .o files. All those object files were then fed to the linker (avr-gcc without the -c option) and it joined them together to make a single file called pfftest.elf. Further steps then took that file as input and used to to create both a listing file and also a .hex file. It's that .hex file that is then programmed into the AVR.

In fact when you hit [Build] inside AS5/6 exactly the same stuff occurs only most of the detail is hidden from you. AS6 takes the list of .c and .S files and uses them, together with other build options you have set in the IDE and creates a Makefile. It then issues the command "make -f Makefile" to have the rules in that file processed just as in my command line example. The Atmel generated Makefile even has those same steps to generate .lss and .hex files. The only thing is that as far as you are concerned you never actually see the Makefile and you don't isse a make command - but it's all happening behind the scenes.

So the key thing when you take a set of .c and .S files that are built with a Makefile (like ffsample.zip or pfsample.zip) is that you need to make sure the options you choose inside a newly created AS5/6 project match what would otherwise be selected by the supplied Makefile.

Quote:

Well i simply added all the files to the project folder and here is an error in usi.S file (i know after fixing it there will be more)

Line:> ldi r24, lo8(F_CPU / 100000) /* Loop counter */
Error:> undefined symbol `F_CPU' in operation


OK well that's because in the Makefile that Chan supplied it had:

DEFS           = -DF_CPU=8000000

and

ASFLAGS        = -Wa,-adhlns=$(<:.S=.lst),-gstabs $(DEFS)
ALL_ASFLAGS    = -mmcu=$(MCU_TARGET) -I. -x assembler-with-cpp $(ASFLAGS)

and

%.o : %.S
        $(CC) -c $(ALL_ASFLAGS) $< -o $@

All of which results in -DF_CPU=8000000 being passed to the assembler when .S files are assembled into .o files.

So you simply have to ensure the same happens in AS5/6. As it happens the way you do that in the IDE is to go to the Properties for the Project and in the section Toolchain-AVR/GNU Assembler-General in the Assembler flags text box enter "-DF_CPU=nnnnnnnnn" without the quotes and with nnnnnnnn replaced by your CPU speed in Hertz.

As F_CPU must be "seen" in usi.S it does not help that you #define'd it in main.c - it needs to be defined in place (or in the case of AS5/6 two places) where it can be seen by all files that are compiled or assembled. What I have just described is where you need to put it for Asm files to see it (but this won't work for .c) however I think that may be all you actually need:

E:\pfsample\avr>grep F_CPU *
Makefile:DEFS           = -DF_CPU=8000000
usi.S:  ldi     r24, lo8(F_CPU / 100000)        /* Loop counter */

E:\pfsample\avr>

It's only usi.S that uses it.

That will clear the error you are seeing and help the code to build.

Quote:

i get: Error 7 region `text' overflowed by 266 bytes

Then you are building it for a CPU it won't fit into. That could be that you don't have the optimisation level set correctly. Again note Chan's Makefile. It has:

OPTIMIZE       = -Os -mcall-prologues

You need to ensure that project options in AS5/6 lead to the same thing being used when the code is built in Studio.

 there is an error regarding DRESULT disk_readp being defined in both mmc.c and diskio.c 

If using SD/MMC cards then you use mmc.c, if using a hard drive you use diskio.c. You do not use both. In my set of files I have:

 Directory of E:\pfsample\avr

01/12/2009  21:21                92 suart.h
01/12/2009  22:15             3,122 suart.S
07/12/2010  20:56            44,033 pff.c
07/12/2010  19:04             8,066 mmc.c
07/12/2010  19:04             1,544 usi.S
24/04/2010  23:45               856 integer.h
09/12/2009  21:45             1,146 diskio.h
07/12/2010  19:03             5,642 main.c
03/12/2010  22:30             1,137 Makefile
07/12/2010  19:29             6,689 pff.h
02/12/2009  22:57             8,112 xitoa.S
07/12/2009  23:11             2,759 xitoa.h
12/12/2009  20:59             2,214 test85.png

No diskio.c there. Also the Makefile has this:

CSRC           = main.c pff.c mmc.c
ASRC           = suart.S xitoa.S usi.S

So again to make your AS5/6 project do the same as the Makefile you need to ensure that only those three .c files and those three .S files are listed in the project. (if you did include diskoi.c this goes some way to explaining the "region `text' overflowed by 266 bytes" error.

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

Very well explained. Thankyou

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

Clawson, if possible, do you have a .mmc file of your SD card which is formatted and has the file poem.txt?
I do not have a sd card right now otherwise according to your instructions i can make .mmc file with winhex.

Your code works perfect even in simulation (apart from some small usart issue which i figured out myself) but i am just using a blank text file renamed as blank.mmc

Once again thankyou.

Edit: If i have to open a file do i have some command to put is hyper terminal or it has to be coded in the program like your version is doing at the moment.

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

Attached is a 2MB file called poem.mmc in a .zip. I simply used vbindiff in Linux to find out where "Mary" was on /dev/sdj1 and then used dd to write the first 2MB which contained that (and just a bit over) to the file from a 1GB SD/MMC card. So this should mount as if it is a 1GB card and you should be able to "see" the file. It seems to work for me in Linux:

clawson@ws-czc1138h0b:~$ sudo losetup /dev/loop0 poem.mmc
clawson@ws-czc1138h0b:~$ sudo mount /dev/loop0 /mnt/foo
clawson@ws-czc1138h0b:~$ ls /mnt/foo
1GB_test.txt  AVRAP003.bin  files.txt  oldtest.wav  poem.txt  test.wav
clawson@ws-czc1138h0b:~$ cat /mnt/foo/poem.txt
Mary had a little lamb,
Its fleece was white as snow,
And every where that Mary went,
the little lamb would go.

clawson@ws-czc1138h0b:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdj1       968M  1.6M  966M   1% /media/E0FD-1813
/dev/loop0      968M  1.6M  966M   1% /mnt/foo
 

Attachment(s): 

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

Just a small note. You can do the mount without losetup, like

$ sudo mount -o loop /tmp/poem.mmc /mnt 
$ ls /mnt
1GB_test.txt*  AVRAP003.bin*  files.txt*  oldtest.wav*	poem.txt*  test.wav*

The first unused loop device will be used.

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

Hello Clawson, the code works as intended. But i am having trouble understanding how can i perform operations that i desire?
For example, using your version of the library, i want to perform couple of following actions, how will i do that?

such as Creating a file, Opening a file, add new data to the opened text file etc

Attachment(s): 

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

If you don't know how filing works then forget FatFs and the AVR for the time being and experiment a bit with the filing functions in stdio.h on your PC (fopen, fread, fwrite, fputc, fseek, flcose, etc). When you know and understand how to create, write and read files using those functions THEN come back to FatFs and you will find the interface is remarkably similar to in fact. There are many many sites and support fora on the internet that will teach you about using stdio filing functions.

For example:

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

That is the description of fseek with some example code but there's similar description/examples for all the functions there. Maybe start with fopen in fact:

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

Here's a much more elaborate example:

http://www.dailyfreecode.com/Cod...

You can use Visual Studio, Pelles C, Code::Blocks or some other PC based C compiler to write programs using these functions and immediately see the effect of running them on your PC (and use advanced debugging tools if you hit problems). This makes it much easier to learn what's going on than trying to use FatFs on an AVR.

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

is it ok if i post some questions relating to it here?

Pages