AT45DB161 and FatFS, restore corrupted filesystem

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

Hey everyone!

Has anyone out there ever tried to tie up FatFS to an AT45DB161?

The question is whether there is a way either not to get into an FS corruption or to get it fixed somehow without reformatting the drive?

For info: we use only 512 bytes out of the 528 available per sector and we perform writing with automatic erase. Also there is a 20k pull-up.

The problem is that after a while the filesystem becomes corrupt: we aren't able to open up a file, either existing or new (returns FR_NOT_READY). f_readdir also fails with the same error, so we can't get the file list.

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

Quote:

we use only 512 bytes out of the 528 available per sector and we perform writing with automatic erase

The plan in Nand for those extra 16 bytes was that you do an ECC over the other 512 then you can tell when data is corrupted during the write and if it cannot be fixed by a second write attempt you remap the failed sector from a sector remap pool (this is what's going on inside an SD/MMC card).

As for fixing it could you somehow map an interface through so that chkdsk/scandisk could see the sectors as if it were a floppy/hard disk and let that sort out the corruption?

However can you just extract a complete binary image of the entire data and post it here? I spent 5 years of my life almost exclusively working on identifying and fixing FAT32 errors so I know a little more than is healthy about the subject ;-)

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

To tell you the truth I am now overwhelmed by an idea of extracting the contents of the flash drive to another location to see what's there :)

Practically, i think I could initiate a byte-to-byte copy of the flash contents to an MMC flash drive that I interface with "Soft-SPI".
But may it be that you can give an idea what the practical use of this is for you?:) The fatfs library says 3 (FR_NOT_READY) and so far I haven't been able to convince it that it isn't (although I cannot recon it is not, and I am more inclined to think that it is) :(

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

Here is the code that we use for the AT45DB161

void at45_select(void)
{
	AT45_PORT &= ~AT45_CS;
}

void at45_release(void)
{
	AT45_PORT |= AT45_CS;
}

// at45db161d read/write
uint8_t at45_rw(uint8_t data)
{
	SPDR = data;
	while (!(SPSR & 0x80)); 
	return SPDR;
}

// initialisation of SPI towards the AT45 chip
void at45_init(void) __attribute__ ((optimize(1)));

void at45_init(void)
{
	// configure pins
	AT45_DDR |= AT45_CS | AT45_MOSI | AT45_SCK;
	AT45_DDR &= ~AT45_MISO;
	AT45_PORT |= AT45_CS;
	// freq SPI CLK/2
	
	SPCR = (1<<SPE)|(1<<MSTR);
	SPSR |= (1<<SPI2X);
	
	// set SPI rate = CLK/64
	/*
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1);
	SPSR &= ~(1<<SPI2X);
	*/
}

// what's our status?
uint8_t at45_status(void)
{
	uint8_t result;
	at45_select();
	at45_rw(0xD7);
	at45_rw(0xFF);
	result = at45_rw(0xFF);
	at45_release();

	return result;
}

// page to buffer
uint8_t at45_read_page_to_buf_1(uint32_t addr_page)
{
	// 4096 - number of pages per AT45DB161D
	//addr_page += 256;
	if(addr_page < 4096)
	{
		at45_select();
		at45_rw(MM_PAGE_TO_B1_XFER);
		at45_rw((char)(addr_page >> 6));
		at45_rw((char)(addr_page << 2));
		at45_rw(0x00);
		at45_release();
		return 0;
	}
	return 1;
}

// copy from the buffer over to the chip
uint8_t at45_write_from_buf_1(uint32_t addr_page) __attribute__ ((optimize(1)));

uint8_t at45_write_from_buf_1(uint32_t addr_page)
{
	// 4096 - number of pages AT45DB161D
	if(addr_page < 4096)
	{
		at45_select();
		at45_rw(B1_TO_MM_PAGE_PROG_W_ERASE); // write data from buffer1 to page 
		at45_rw((uint8_t)(addr_page>>6));
		at45_rw((uint8_t)(addr_page<<2));
		at45_rw(0x00);
		at45_release();
		return 0;
	}
	return 1;
}

// copying from BUFFER1 to RAM
void at45_read_from_buf_1(uint8_t * dst, uint32_t count, uint16_t addr)
{
	uint32_t i = 0;
	at45_select();
	at45_rw(BUFFER_1_READ);                 
	at45_rw(0x00);
	at45_rw((uint8_t)(addr>>8));
	at45_rw((uint8_t)addr);
	at45_rw(0x00);
	while(count--) dst[i++] = at45_rw(0xFF);
	at45_release();
}

// transferring the data over to BUFFER 1
void at45_write_to_buf_1(const uint8_t *src, uint32_t count, uint16_t addr) __attribute__ ((optimize(1)));

void at45_write_to_buf_1(const uint8_t *src, uint32_t count, uint16_t addr)
{
	uint32_t i = 0;
	at45_select();
	at45_rw(BUFFER_1_WRITE);                 
	at45_rw(0x00);
	at45_rw((uint8_t)(addr>>8));
	at45_rw((uint8_t)addr);
	//at45_rw(0x00);
	while(count--) at45_rw(src[i++]);
	at45_release();	

}


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

Our code tries to write a file at controller startup and if it fails it raises the failure flag on the chip and doesn't use it. So I noticed that after some restarts it doesn't fail out the AT45DB. I remember I read somewhere that the memory states may vary after certain types of restarts.
May that be the case?
But anyway after a restart in the init1 section we do:

	uint16_t *p = (uint16_t*) 0x100;
	
	while((uint16_t)p < RAMEND)
		*p++ = 0;

That doesn't seem to be very much of help.

May anyone have suggestions?

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

There's no need to do that initialisation. Anything in .data will be initialised from flash and anything in .bss is automatically wiped to 0 by the CRT. I imagine any sector buffer you use with the AT45 will be a global buffer so will be in .bss and wiped anyway.

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

The .bss section in our scenario is aligned in the external memory, along with other sections dedicated to buffers. However, I've noticed that depending on the sort of restart, the behaviour may vary.