Yahoo Groups archive

AVR-Chat

Index last updated: 2026-04-28 22:41 UTC

Message

Re: Atmel Data Flash

2005-10-29 by raimond712002

The file below is my dataflash library. It is a professional 
implementation, but I can make it open source here because you
can't know the real application (which is very big).
Some comments: SPI is mode 3, I can't remember why, but I can 
remember this was a 'must' at that time. GCC please.

Check the SPI pins, they are used for programming the mega32 too. 
Check the 3.3V power for the dataflash chip.
Good luck!

/*====================================================================
====================
                            AT45DB041 DataFlash Library
Chip: ATMEGA64
Freq: 4.9152 MHz
======================================================================
==================*/
#include <string.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include "type.h"
#include "rtos.h"
#include "dataflash.h"

/*                NVDS EEPROM MEMORY - 16bit locations

NVDS Memory = High endurance eeprom memory, soft implemented, 16bit.
One high endurance 16bit location is maintained by an eeprom array 
organized 
as follow:
 - first byte is the direction byte (0xFF=ahead, 0x00=back).
 - FACTOR-1 bytes as moving flags.
 - FACTOR words for storage.

So, for one 16bit high endurance eeprom location, it is consumed 
FACTOR*3 
eeprom bytes! FACTOR is the multiplication endurance factor for the 
internal
eeprom. So, if the internal eeprom has an 100,000 writes endurance, 
a FACTOR = 100 will make the 16bit value have 10,000,000 writes 
endurance! 
(but with the expense of 300 bytes of eeprom for only one 16bit 
value!).

The eeprom array need not be initialized. Anyway, first reading the 
value 
after reset with ReadNVDS() function should be compared against 
permissible 
range (if any).
*/

#define FACTOR	16

/* Search the last flag != 0xFF in eeprom (16 flags zone)
   Return the address of the high byte of the value */
   
static char search_last(char *eetab)
{
	char i;
	
	for (i = FACTOR-1; i; i--) {
		if (eeprom_read_byte(eetab+i) != 0xff) break;
	}
	return i;
}


static void write_ahead(char *eetab, char index, uint val)
{
	eeprom_write_byte(eetab+FACTOR+index*2+2, (char)(val>>8));
	eeprom_write_byte(eetab+FACTOR+index*2+3, (char)val);
	eeprom_write_byte(eetab+index+1, 0x00);
}


static void write_back(char *eetab, char index, uint val)
{
	eeprom_write_byte(eetab+FACTOR+index*2-2, (char)(val>>8));
	eeprom_write_byte(eetab+FACTOR+index*2-1, (char)val);
	eeprom_write_byte(eetab+index, 0xff);	
}


void WriteNVDS(char *eetab, uint val)
{
	char i;
	
	i = search_last(eetab);
	if (eeprom_read_byte(eetab) == 0xff) { 	/* DIR = ahead */
		if (i != FACTOR-1) {				/* 
It's not last */
			write_ahead(eetab, i, val);
		} else {					
		/* Last pointer */
			write_back(eetab, i, val);
			eeprom_write_byte(eetab, 0x00);	/* DIR -> 
back */
		}
	} else {						
		/* DIR = back */
		if (i) {					
		/* It's not first */
			write_back(eetab, i, val);
		} else {					
		/* First pointer */
			write_ahead(eetab, i, val);
			eeprom_write_byte(eetab, 0xff);	/* DIR -> 
ahead */
		}
	}
}


uint ReadNVDS(char *eetab)
{
	char i;
	
	i = search_last(eetab) * 2;
	return ((uint)eeprom_read_byte(eetab+FACTOR+i)<<8) + 
eeprom_read_byte(eetab+FACTOR+i+1);
}


/* SPI port */

/* Enables spi port in master mode. 
   Direction for bits are set in main() */
   
void spi_init()
{
 	SPCR = 0x5C; 		/* MODE 3, Master, fastest rate, no 
intr. */
  	SPSR = 1;			/* X2 clk */
}


/*	Shifts one byte on the spi port. */

void wrspi(char c)
{
  	SPDR = c;
  	while (!(SPSR & (1<<SPIF)));
}


char rdspi()
{
  	SPDR = 0;
  	while (!(SPSR & (1<<SPIF)));
  	return SPDR;
}


/*                            DATA FLASH

Reading and writing to DataFlash device is implemented in a circular 
fashion.
There are two pointers, one for reading and one for writing. The 
DataFlash
device contains 2048 pages, each page containing two records. So, 
there are 
4096 records, 132 bytes each. 

Because the writing is done in a circular fashion, the wearing is 
assured
(every page must be updated once per 10000 writes in that sector). 
Because 
the (larger) sector has 512 pages, a page is updated once every 512 
writes, 
so this is OK.

Pointers for in and out are maintained in a high endurance eeprom 
area, 
because they must be updated every record write/read from DataFlash. 
High endurance eeprom is achieved in software, every high endurance 
16bit 
location consuming an array in eeprom. See high endurance eeprom 
section.
*/

uint DFPin, DFPout;				/* pointers in 
dataflash */
char EETin[48] eeprom;			/* memorized in high 
endurance eeprom */
char EETout[48] eeprom;


void DFPin_read()
{
	DFPin = ReadNVDS((char*)EETin);
	if (DFPin >= 4096) DFPin = 0;
}


void DFPout_read()
{
	DFPout = ReadNVDS((char*)EETout);
	if (DFPout >= 4096) DFPout = 0;
}


void DFPin_write()
{
	WriteNVDS((char*)EETin, DFPin);
}


void DFPout_write()
{
	WriteNVDS((char*)EETout, DFPout++);
}


/* Inits the DataFlash device. 
   Must be called only once, after reset. */
   
void df_init()
{
	spi_init();
	DFPin_read();
	DFPout_read();
}


#define SS0	clr(PORTB,0) 		/* CS low */
#define SS1	set(PORTB,0) 		/* CS high */

void df_ready()
{
	char stat;

	for (;;) {
		SS0; 
		wrspi(0x57); 			/* opcode */
		stat = rdspi();			/* read status byte */
		SS1;
		if (stat & 0x80) break; /* ready */
		os_pause();
	}
}


/* Writes a block of data (132bytes = 1/2page) to the DataFlash 
device. 
   The write is controlled by the DFPin pointer. Before calling,
   check if there is space left in dataflash!
   src: source array.
   Usage: if (!df_full()) df_write(src); */

void df_write(char *src)
{
	uchar i, BFA;
  
	BFA = (DFPin & 1) ? 132 : 0; 		/* buffer address */
	
	/* Main memory to buffer1 transfer: 
	   \ [0x53] [0000.PPPP] [PPPP.PPPx] [xxxx.xxxx] / */
	df_ready();
	SS0; 
	wrspi(0x53); 						/* 
opcode */
	wrspi(DFPin>>8); 					/* 
address */
	wrspi(DFPin); 
	wrspi(0); 
	SS1;
	
	/* Write src to buffer1: 
	   \ [0x84] [0000.xxxx] [xxxx.xxxB] [BBBB.BBBB] ...data... / 
*/	   
	df_ready();
	SS0; 
	wrspi(0x84); 						/* 
opcode */
	wrspi(0); 						
	/* address */
	wrspi(0); 
	wrspi(BFA); 
	for (i = 0; i < 132; i++) {
		wrspi(src[i]);					/* 
data */
	}
	SS1;

	/* Buffer program with builtin erase: 
	   \ [0x83] [0000.PPPP] [PPPP.PPPx] [xxxx.xxxx] / */
	df_ready();
	SS0; 
	wrspi(0x83);						/* 
opcode */
	wrspi(DFPin>>8);					/* 
address */
	wrspi(DFPin); 
	wrspi(0);
	SS1;
	DFPin = (DFPin + 1) & 4095; 		/* Update in pointer 
*/
	DFPin_write();
}


/* Reads a block of data from the DataFlash device. The read is 
controlled
   by the DFPout pointer. 132 bytes are read. Before calling, check 
if there
   are still records in dataflash!
   dst: the address of the buffer where to put the bytes read.
   Usage: if (!df_empty()) df_read(dst); */
   
void df_read(char *dst)
{
	uchar i, BFA;
	
	BFA = (DFPout & 1) ? 132 : 0; 		/* buffer address */
	
	/* Main memory to buffer1 transfer: 
	   \ [0x53] [0000.PPPP] [PPPP.PPPx] [xxxx.xxxx] / */  
	df_ready();
	SS0; 
	wrspi( 0x53 ); 						/* 
opcode */
	wrspi( DFPout >> 8 ); 				/* address */
	wrspi( DFPout ); 
	wrspi( 0 ); 
	SS1;
	
	/* Read buffer1 to dst: 
	   \ [0x54] [0000.xxxx] [xxxx.xxxB] [BBBB.BBBB] 
[x] ...data... / */
	df_ready();
	SS0; 
	wrspi( 0x54 ); 						/* 
opcode */
	wrspi( 0 );						
	/* address */
	wrspi( 0 ); 
	wrspi( BFA ); 
	wrspi( 0 ); 						/* 
don't care */
	for (i = 0; i < 132; i++) {
		dst[ i ] = rdspi(); 			/* data */
	}
	SS1;
	DFPout = (DFPout + 1) & 4095; 		/* Update out pointer 
*/
	DFPout_write();
}


/* Get the number of records stored in DataFlash */

uint df_records()
{
	return (DFPin - DFPout + ((DFPin < DFPout) ? 4096 : 0));
}


/* Get the EMPTY flag.
   DataFlash is empty, we have nothing to read. */
   
char df_empty()
{
	return (df_records() == 0);
}


/* Get the FULL flag.
   DataFlash is full, we cannot write anymore. */
char df_full()
{
	return (df_records() == 4095);
}

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.