FatFs disk_timerproc problem

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

Hi all. sorry for asking again, but im searching on google seems not found any clue for this.

in attempt to testing FatFs i turn off disk_timerproc() and i get my program works fine.

but when im using disk_timerproc() my program end up with STA_NOINIT, STA_NODISK and STA_PROTECT when using disk_initialize. so i check on elmchan site about disk_initialize and found

 

Application program MUST NOT call this function, or FAT structure on the volume can be broken. To re-initialize the file system, use f_mount function instead.

i don't know about this before, because im using  

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

and i use AtMega328 on 8Mhz internal clock using 

    OCR0A = 0x4D;
    TIMSK0 = (1 << OCIE0A); 
    TCCR0A = (1 << WGM01); 
    TCCR0B = (1 << CS00) | (1 << CS02);

to generate 10 ms timer interrupt 

 

and this is port controls on mmc.c

 

/* Port controls  (Platform dependent) */
#define SS      (1<<PB0)
#define MOSI      (1<<PB3)
#define MISO       (1<<PB4)
#define SCK     (1<<PB5)
#define CS_LOW()    PORTB &= ~SS            /* CS=low */
#define    CS_HIGH()    PORTB |= SS            /* CS=high */
//#if 0
#define SOCKINS        (!(PINB & 0x01))    /* Card detected.   yes:true, no:false, default:true */ //sdcs 0x01
#define SOCKWP        (PINB & 0x08)        /* Write protected. yes:true, no:false, default:false */ //mosi 0x08
//#endif 
#define    FCLK_SLOW()    SPCR = 0x52        /* Set slow clock (F_CPU / 64) */
#define    FCLK_FAST()    SPCR = 0x50        /* Set fast clock (F_CPU / 2) */

so my problem is when i turn off disk_timerproc(), my program works fine. but when i using / activating disk_timerproc() i stuck on disk_initialize. i want to checking the sd card before writing data to mmc.

and the second question, is that ok if im using disk_initialize in my looping program to checking mmc?

Last Edited: Sun. Jan 31, 2016 - 11:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

anyone can help me?

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

zu_adha wrote:
so my problem is when i turn off disk_timerproc(), my program works fine.

Have you actually looked at what disk_timerproc does? It has several functions:

 

1) it ticks down some "timers". Fatfs uses these internally for timeouts. So if you don't enable disk_timerproc() and the code hits some circumstance where it would "get stuck" it will never timeout if the timers are not running.

 

2) it reads the state of the "card present" sensor every 10ms. This so that if the card is removed the situation will be recognised almost immediately. If it does not read "card present" it will set the STA_NOINIT state to say "there is no longer an initialised card present". The other FatFs functions will then refuse to operate while in this condition. If you stop disk_timerproc() it will not notice this event.

 

3) when disk_timerproc() runs every 10ms it checks the state of the write protect signal from the switch on the card socket. So if a card is write protected it sets condition STA_PROTECT and no function that would attempt to modify the card is allowed to run.

 

It would be VERY unwise not to have disk_timerproc() working. If by enabling it you are seeing STA_NOINIT or STA_PROTECT it suggests that the code in disk_timerproc() that reads the state of the CP and WP signals is not getting the correct result. Do you even have those signals from the card socket wired up? if you do are they connected to the same I/O pins that the code is checking? as you can see from:

#define SOCKINS        (!(PINB & 0x01))    /* Card detected.   yes:true, no:false, default:true */ //sdcs 0x01
#define SOCKWP        (PINB & 0x08)        /* Write protected. yes:true, no:false, default:false */ //mosi 0x08

it is expecting the Card Present signal to be wired to bit 0 of PINB and Write Protect to be wired to bit 3 of PINB. If you have the signals wired to other pins then change these two lines to check the right port and the right bits.

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

clawson wrote:

zu_adha wrote:
so my problem is when i turn off disk_timerproc(), my program works fine.

Have you actually looked at what disk_timerproc does? It has several functions:

 

1) it ticks down some "timers". Fatfs uses these internally for timeouts. So if you don't enable disk_timerproc() and the code hits some circumstance where it would "get stuck" it will never timeout if the timers are not running.

 

2) it reads the state of the "card present" sensor every 10ms. This so that if the card is removed the situation will be recognised almost immediately. If it does not read "card present" it will set the STA_NOINIT state to say "there is no longer an initialised card present". The other FatFs functions will then refuse to operate while in this condition. If you stop disk_timerproc() it will not notice this event.

 

3) when disk_timerproc() runs every 10ms it checks the state of the write protect signal from the switch on the card socket. So if a card is write protected it sets condition STA_PROTECT and no function that would attempt to modify the card is allowed to run.

 

It would be VERY unwise not to have disk_timerproc() working. If by enabling it you are seeing STA_NOINIT or STA_PROTECT it suggests that the code in disk_timerproc() that reads the state of the CP and WP signals is not getting the correct result. Do you even have those signals from the card socket wired up? if you do are they connected to the same I/O pins that the code is checking? as you can see from:

#define SOCKINS        (!(PINB & 0x01))    /* Card detected.   yes:true, no:false, default:true */ //sdcs 0x01
#define SOCKWP        (PINB & 0x08)        /* Write protected. yes:true, no:false, default:false */ //mosi 0x08

it is expecting the Card Present signal to be wired to bit 0 of PINB and Write Protect to be wired to bit 3 of PINB. If you have the signals wired to other pins then change these two lines to check the right port and the right bits.

hi Clawson thanks for feed back

1.) yes i already know this, thats why when i want to apply foolproof i disable this feature, so i know where the code is get stuck without disk_timeproc fired up for debugging purpose. but the problem when everything's ok, i want this feature back, as like you said its very unwise if i turn it off, but the problem when i turn it on, my program stuck on initialize card and cannot write / read the file. it give me  STA_NOINIT, STA_NODISK and STA_PROTECT on same wiring and same program that mmc just work fine to write and read. only disable disk_timeproc.
 

2.) i know this feature, so why i generate 10ms timer to fired up disk_timerproc. but with same wiring same program only disk_timerproc that i turn on it wont start to write or read. so maybe the problem is in wiring?
 

3.)what is stat cp and cw? i can't find that in the files. i dont know about sockins and sockwp pin, i just use sockin as i used on sdcs on mmc pin (PINB0 on m328) as your program using PB4 as sdcs and sockin pin on m32. and sockwp is the same pin as mosi on mmc too as your program on m32 using PB5 (mosi). i have not check the pin signal, but if something goes wrong, it will not detect at first try, because that pin is SPI pin on mmc (mosi and sdcs). 

Last Edited: Mon. Feb 1, 2016 - 06:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zu_adha wrote:
what is stat cp and cw? i can't find that in the files

This is my WHOLE POINT:

 

CP = Card Protect

WP = Write Protect

 

When you look at a standard SD/MMC card socket:

 

http://www.jianpingusa.com/images/sdmmc.jpg

 

You can see what they call "WP and "CD" ("Card Detect" I guess) towards the left of those signals/ They are two detector switches that monitor (a) if the little slide switch on the edge of the SD card is in the "Write Protect" position and also another detects simply if there is a card inserted in the socket. As I say the software uses these to (a) know if there is a card there (STA_NOINIT if not) and (b) whether it is allowed to write back (STA_PROTECT)

 

So either you are using a socket that has these signals and you have wired them to input pins on your AVR so it can monitor their state.

 

Or else you are using a "cut-down" socket (perhaps a micro-SD rather than SD/MMC socket?) that simply does not have these.

 

In the latter case you need to take the code that is provided for disk_timerproc():

void disk_timerproc (void)
{
        BYTE n, s;


        n = Timer1;                             /* 100Hz decrement timer */
        if (n) Timer1 = --n;
        n = Timer2;
        if (n) Timer2 = --n;

        s = Stat;

        if (MMC_WP)                             /* Write protected */
                s |= STA_PROTECT;
        else                                    /* Write enabled */
                s &= ~STA_PROTECT;

        if (MMC_CD)                             /* Card inserted */
                s &= ~STA_NODISK;
        else                                    /* Socket empty */
                s |= (STA_NODISK | STA_NOINIT);

        Stat = s;                               /* Update MMC status */
}

(or similar) and simply remove all the lines I highlighted. Perhaps replacing them as:

void disk_timerproc (void)
{
        BYTE n, s;


        n = Timer1;                             /* 100Hz decrement timer */
        if (n) Timer1 = --n;
        n = Timer2;
        if (n) Timer2 = --n;

        Stat = 0x00;                               /* Update MMC status */
}

In effect you are lying and saying "there's always a card and it's always write enabled". The software will go wrong if either is ever not true.

 

If you think you have got Card Present and Write Protect signals and yet "Stat" is wrongly getting set wit hSTA_NOINIT, STA_NODISK, STA_PROTECT then, like I say you are probably reading the WRONG input lines. Which is why I said to check:

#define SOCKINS        (!(PINB & 0x01))    /* Card detected.   yes:true, no:false, default:true */ //sdcs 0x01
#define SOCKWP        (PINB & 0x08)        /* Write protected. yes:true, no:false, default:false */ //mosi 0x08

That is saying the present switch is on PB0 and the protect switch is on PB3. If the signals from the card socket are attached to other AVR pins you need to change these two #defines to match.

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

thanks a lot clawson... and yes my SD card socket does not have WP and CD pin, neither on my mmc card socket. im using this module https://www.avrfreaks.net/forum/a...

so once again thanks for pointing the pin, at first i thought FasFs checking mmc present by scaning is there FAT detected with SPI protocol. so it was a simple pin detected...

so can i rely on disk_initialize or/and f_mount feed back before write/read the file? can i call disk_initialize on my loop routine? because elm chan site says "http://elm-chan.org/fsw/ff/en/di..."

 Application program MUST NOT call this function, or FAT structure on the volume can be broken. To re-initialize the file system, use f_mount function instead.

and the second question  

if my socket does not have CD and WP pin can i disable disc_timerproc and disable this line

#define SOCKINS        (!(PINB & 0x01))    /* Card detected.   yes:true, no:false, default:true */ //sdcs 0x01
#define SOCKWP        (PINB & 0x08)        /* Write protected. yes:true, no:false, default:false */ //mosi 0x08

 

instead using this : ?
 

void disk_timerproc (void)
{
        BYTE n, s;


        n = Timer1;                             /* 100Hz decrement timer */
        if (n) Timer1 = --n;
        n = Timer2;
        if (n) Timer2 = --n;

        Stat = 0x00;                               /* Update MMC status */
}

 

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

zu_adha wrote:
so can i rely on disk_initialize or/and f_mount feed back before write/read the file?

Not sure what you mean. The calling sequence to FatFs should always be f_mount() first and don't continue if that does not give FR_OK. If you want to get an "early" look at whether the card is even detected you can call disk_initalize() directly, before you make the call to f_mount() but if you are past the early debug stage and already know the disk_initialize() will work then you don't need to call it directly as f_mount() will call it anyway when it finds that Stat & STA_NOINIT != 0.

zu_adha wrote:
if my socket does not have CD and WP pin
If the socket does not have those then forget the #define of SOCKINS/SOCKWP all together as those simply won't be used and yes, you should modify the code in disk_timerproc() to just replace all that detection stuff with "Stat = 0x00;".

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

 

clawson wrote:
If the socket does not have those then forget the #define of SOCKINS/SOCKWP all together as those simply won't be used and yes, you should modify the code in disk_timerproc() to just replace all that detection stuff with "Stat = 0x00;

 

all right thanks...

what about if im not calling the disk_timerproc()? then replacing stat = 0x00? since i don't have CD/WP pins, so i can save the timer, or will have any disadvantage if i don't call disk_timerproc() although i don't have CD/WP pins?

Last Edited: Wed. Feb 3, 2016 - 09:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zu_adha wrote:
what about if im not calling the disk_timerproc()?
That is not an option because of:

        n = Timer1;                             /* 100Hz decrement timer */
        if (n) Timer1 = --n;
        n = Timer2;
        if (n) Timer2 = --n;

that must happen.

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

clawson wrote:

zu_adha wrote:
what about if im not calling the disk_timerproc()?
That is not an option because of:

        n = Timer1;                             /* 100Hz decrement timer */
        if (n) Timer1 = --n;
        n = Timer2;
        if (n) Timer2 = --n;

that must happen.

 

i read about someone else posting about this before, but i forgot where : so in term logging data i need to save the battery, so most of time i sleep the uC and if timer waking up every 10ms the interrupt, will be significant for battery consumption.

so my question :

 

1. what exactly FatFs need the 100Hz timer for? i tough before just for checking CD and WP only.

2. why when i turn off the timer i can still do initialize, read and write ? is there any system failure if i turn off disk_timeproc? (btw i'll check the code too but im afraid if im wrong)

3. so on what state i can safely turn off the timer interrupt that calling in disk_timerproc ?

Last Edited: Wed. Feb 3, 2016 - 09:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) those are count-down timers. FatFs uses them internally when it issues an SD command it thinks might never respond. To prevent it waiting indefinitely for a response it uses either "Timer1" or "Timer2" and does something like:

Timer2 = 100;
issse_cmd();
while(no_response && Timer2);

this relies on the fact that Timer2 will tick away in the background every 10ms or whatever. So the delay here will be a maximum of 1 second if 'no_response' persists. You can see this kind of thing in the actual code:

$ grep Timer1 *
mmc_avr.c:BYTE Timer1, Timer2;	/* 100Hz decrement timer */
mmc_avr.c:		for (Timer1 = 2; Timer1; );	/* Wait for 20ms */
mmc_avr.c:		for (Timer1 = 20; Timer1; );	/* Wait for 20ms */
mmc_avr.c:	Timer1 = 20;
mmc_avr.c:	} while ((token == 0xFF) && Timer1);
mmc_avr.c:		Timer1 = 100;						/* Initialization timeout of 1000 msec */
mmc_avr.c:				while (Timer1 && send_cmd(ACMD41, 1UL << 30));	/* Wait for leaving idle state (ACMD41 with HCS bit) */
mmc_avr.c:				if (Timer1 && send_cmd(CMD58, 0) == 0) {		/* Check CCS bit in the OCR */
mmc_avr.c:			while (Timer1 && send_cmd(cmd, 0));			/* Wait for leaving idle state */
mmc_avr.c:			if (!Timer1 || send_cmd(CMD16, 512) != 0)	/* Set R/W block length to 512 */
mmc_avr.c:	n = Timer1;				/* 100Hz decrement timer */
mmc_avr.c:	if (n) Timer1 = --n;

2) the timers are a protection (for example suppose the card is either not present or is not quite pushed in and is only making intermittent contact). If they aren't active and something goes wrong then the code will effectively "lock up" forever.

 

3) you would need to analyse where the driver is using "Timer1" and "Timer2" and just ensure they are always running when any function that makes use of them is called. This might just be disk_initialize() but I haven't looked and perhaps disk_read() and disk_write() also use them.

 

EDIT: I've looked now - The two timers are used in more than just the init(), they are also involved in providing delays in both reading and writing. And it's not just the low level "has SPI responded?" kind of delay but he also uses them at a higher level when, for example, he is giving the card a chance to power up or down. See also, for example, wait_ready(). The "wait" in that is using one of the two timers.

Last Edited: Wed. Feb 3, 2016 - 09:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So in short i can disable the timer as long as i'm not communicate with mmc, is that right ?
and if i want to communicate with mmc (lets say write some data) just before i call the function for writing i have to enable the timer, and when the write sequence done with no error, i can turn off again.

 

And, as i see the code, timer 1 and timer 2 is generate by one timer on microcontroller right?  (not using both timer on m328)

Last Edited: Wed. Feb 3, 2016 - 10:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah on the face of it that *should* work. I don't think FatFs is clever enough (like the disk support in most operating systems) to flush buffered data in the background, indeed to do so would require it to be called on interrupts, so you should be OK only having the timer running when you make any f_*() calls.

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

many thanks clawson, yes

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

zu_adha wrote:
So in short i can disable the timer as long as i'm not communicate with mmc, is that right ?

I don't really understand your reluctance.  Say 10us every 10ms to service -- 0.1% of AVR.  And don't you need a timer tick in any real app anyway?  I do in all of mine...

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:
I don't really understand your reluctance.  Say 10us every 10ms to service -- 0.1% of AVR.  And don't you need a timer tick in any real app anyway?  I do in all of mine...

 

i mean if my program sleep for 1 second and wake up, so in 1 second sleep, the timer is not ticking, so if i disable the disk_timeproc while the microcontroller sleep it can save a lot of power and flash to babysitting in disk_timerproc. or did i make something wrong?

 

and what do you mean by "And don't you need a timer tick in any real app anyway"? what is real app stand for? sorry, english is not my first language maybe you can give me an example for this.

 

 

note : or maybe in another project i wake up the microcontroller by external interrupt pin, so when in sleep mode i don't need to wake up just to give disk_timeproc 10ms pulse. btw i need your opinion, it will make me better to understand how it works. thanks btw.

Last Edited: Wed. Feb 3, 2016 - 08:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

you should modify the code in disk_timerproc() to just replace all that detection stuff with "Stat = 0x00;".

hi clawson i have a problem with replacing Stat = 0x00. (program get stuck while no mmc in the slot).

but with

 

BYTE n, s;

    s = Stat;
    
    n = Timer1;                             /* 100Hz decrement timer */
    if (n) Timer1 = --n;
    n = Timer2;
    if (n) Timer2 = --n;

    Stat = s;

 is works fine, so maybe you can't put 'Stat' with a 'value', but must with 's'.

cheers..

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

Perhaps it's just easiest to remove all references to "Stat" from that timer routine then?

i mean if my program sleep for 1 second and wake up, so in 1 second sleep, the timer is not ticking,

I wonder if you missed the point Lee was making? Take a look at what actually happens in this timer interrupt. If checks two variables for non-zero and if either is it gets decremented. Together with the code to get into and out of the ISr you are maybe looking at 50 machine cycles. At 1MHz that would happen in 50us. It happens 100 times per second. So 5ms in every 1000ms or 0.5% of the time.

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

clawson wrote:
Perhaps it's just easiest to remove all references to "Stat" from that timer routine then?

 

i don't think so, because if i have CD/WP pin on next project is not hard to re-enable again. so... will my code works? because i have an error/stuck when i change Stat = 0x00; but not with this:

BYTE n, s;

    s = Stat;

    n = Timer1;                             /* 100Hz decrement timer */
    if (n) Timer1 = --n;
    n = Timer2;
    if (n) Timer2 = --n;

    Stat = s;

so.. FatFs still not have a simple feature to disable CD/WP pin (especially for Stat) as simple as if i change on ffconf.h, because until this day i don't know that was a WP pin (i already know CD pin before but not using it, since there is a lot of module on ebay that has not CD/WP pin then the module that has one).

clawson wrote:
I wonder if you missed the point Lee was making? Take a look at what actually happens in this timer interrupt. If checks two variables for non-zero and if either is it gets decremented. Together with the code to get into and out of the ISr you are maybe looking at 50 machine cycles. At 1MHz that would happen in 50us. It happens 100 times per second. So 5ms in every 1000ms or 0.5% of the time.

 

yup maybe i miss something, Lee was right btw about time consumption (btw who is Lee? theusch?). But in my case now, its just simple if i disable all peripheral from ADC,BOD, pull up on GPIO, including timer and wake up only with watch dog right?  

 

and i mean, yes i always using the disk_timerproc as long as the mcu is not in sleep mode, even if i'm not writing or read, because not only like Lee's said but it simple in the code too. and then disable when mcu is want to sleep.

 

 

note : im still not yet looking on PetitFatFs since it can works with attiny85 so ElmChan must be disable CD/WP pin and Stat register... 

Last Edited: Thu. Feb 4, 2016 - 07:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zu_adha wrote:
i don't think so, because if i have CD/WP pin on next project is not hard to re-enable again

This is the exact reason God invented #ifdef. If some code is inside a #ifdef and that thing is not defined then it's like the lines don't exist as far as the C compiler is concerned.

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

clawson wrote:
This is the exact reason God invented #ifdef. If some code is inside a #ifdef and that thing is not defined then it's like the lines don't exist as far as the C compiler is concerned.

 

yup.. im using that on, but what i mean is, i have not yet looking whole entire inside FatFs so i dont have any clue 'Stat' is using when, where and for what else, because i get stuck/error when try to put Stat = 0x00, so is save and simple to me if i just using :

#define CS_LOW()	PORTB &= ~SS			/* CS=low */
#define	CS_HIGH()	PORTB |= SS			/* CS=high */
#if 0
#define SOCKINS		(!(PINB & 0x01))	/* Card detected.   yes:true, no:false, default:true */ //sdcs 0x01
#define SOCKWP		(PINB & 0x08)		/* Write protected. yes:true, no:false, default:false */ //mosi 0x08
#endif 
#define	FCLK_SLOW()	SPCR = 0x52		/* Set slow clock (F_CPU / 64) */
#define	FCLK_FAST()	SPCR = 0x50		/* Set fast clock (F_CPU / 2) */

and this :

void disk_timerproc (void)
{
	BYTE n, s;

	n = Timer1;				/* 100Hz decrement timer */
	if (n) Timer1 = --n;
	n = Timer2;
	if (n) Timer2 = --n;

	s = Stat;
#if 0
	if (SOCKWP)				/* Write protected */
		s |= STA_PROTECT;
	else					/* Write enabled */
		s &= ~STA_PROTECT;

	if (SOCKINS)			/* Card inserted */
		s &= ~STA_NODISK;
	else					/* Socket empty */
		s |= (STA_NODISK | STA_NOINIT);
#endif
	Stat = s;				/* Update MMC status */
}

instead by "remove all references to "Stat" from that timer routine" (or maybe i miss something with exactly what you mean...cheers),

but i don't know if i have more trouble using this, since i don't have yet looking inside FatFs, that why i ask here, but i got program stuck with Stat = 0x00.

 

Last Edited: Fri. Feb 5, 2016 - 12:27 PM