本程序为AVR单片机SPI口访问AT45DB161D提供一组接口函数,通过这一组接口函数可非常容易的完成对AT45DB161D的读写操作.
AT45DB161D按页组织和操作(读写擦等等)内部的FLASH存储器,每页为528字节(特殊用途时可通过命令配置成512字节),其内部共集成4096页,即4096*528=2162688字节。本程序将为您提供读写这2162688字节存储区的线性操作方法。使用这些函数,用户可不必考虑AT45DB161D内部的存储器组织结构,如同读写一个文件一样进行读写操作。
void df_init(void); 这是SPI口初始化函数,它必须在所有这些接口函数调用之前得到调用
void df_read_open(uint32_t addr); 读操作初始化函数,addr指定接下来的读函数的开始读取位置。程序内部维护一个当前读取计数器,用户每读一字节该计数器加一
void df_write_open(uint32_t addr); 写操作初始化函数,addr指定接下来的写函数的开始写入位置。程序内部维护一个当前写入计数器,用户每写入一个字节该计数器加一
uint8_t df_getc(void); 此函数从当前读位置读取一字节后返回,内部的读计数器加一
void df_putc(uint8_t c); 此函数向当前写位置写入一字节的数据,并使内部写计数器加一
void df_read(uint8_t *buf,uint8_t size); 此函数从当前读位置读取size个字节的数据到缓冲区buf,并使内部读计数器加size
void df_write(uint8_t *buf,uint8_t size); 此函数从缓冲区buf向当前写位置写入size字节的数据,并使内部写计数器加size
void df_read_seek(uint32_t addr); 调整当前读计数器,调用此函数前必须已调用df_read_open
void df_write_seek(uint32_t addr); 调整当前写计数器,调用此函数前必须已调用df_write_open
void df_read_close(void); 关闭读操作
void df_write_close(void); 关闭写操作,所有的写入操作完成后必须调用此函来结束写操作,以便数据能够完整的保存到AT45DB161D主存储器当中
源程序:
/********************************** AVR单片机SPI口读写at45db161d接口程序 文件名:dataflash.c 编译:WinAVR-20070525
芯艺设计室 2004-2007 版权所有 转载请保留本注释在内的全部内容 WEB: Email: changfutong@sina.com **********************************/
#i nclude #i nclude "at45db161d.h" #i nclude "dataflash.h"
/*****下面是全局变量定义******/ static uint16_t g_CurReadPage;//当前读的页地址 static uint16_t g_CurReadByte;//当前读的字节(页中地址) static uint16_t g_CurWritePage;//当前写的页地址 static uint16_t g_CurWriteByte;//当前写的字节地址(页中地址)
/*****下面是内部调用的接口函数******/
//从SPI口输出一字节数据 static uint8_t spi_write(uint8_t data) { SPDR = data; while(!(SPSR & _BV(SPIF))); return SPDR; }
//检测并等待器件忙状态,8引脚封闭器件没有 RDY/BUSY引脚 为些通过读状态寄存器来检测忙状态 static void df_wait_busy(void) { SELECT_CHIP; spi_write(STATUS_REGISTER); while(1) { if(spi_write(0) & 0x80) //读取的最高位0时器件忙 break; } UNSELECT_CHIP; }
//读主存储器指定页到读缓冲区(BUFFER1) static void load_page_to_buffer(uint16_t page,uint8_t buffer) { SELECT_CHIP;
if(buffer == DF_READ_BUFFER) spi_write(MM_PAGE_TO_B1_XFER); else spi_write(MM_PAGE_TO_B2_XFER); spi_write((uint8_t)(page >> 6)); spi_write((uint8_t)(page << 2)); spi_write(0x00);
UNSELECT_CHIP;
df_wait_busy(); }
//将写缓冲区内容写入到主存储器中指定页 static void write_page_from_buffer(uint16_t page,uint8_t buffer) { SELECT_CHIP;
if(buffer == DF_WRITE_BUFFER) spi_write(B2_TO_MM_PAGE_PROG_WITH_ERASE); else spi_write(B1_TO_MM_PAGE_PROG_WITH_ERASE); spi_write((uint8_t)(page>>6)); spi_write((uint8_t)(page<<2)); spi_write(0x00); // don't cares
UNSELECT_CHIP;
df_wait_busy(); }
//从读缓冲区读数据 static void read_buffer(uint16_t addr,uint8_t *data,uint8_t size) { uint8_t i;
SELECT_CHIP;
spi_write(BUFFER_1_READ); spi_write(0x00); spi_write((uint8_t)(addr>>8)); spi_write((uint8_t)addr); for(i=0;idata[i]=spi_write(0);
UNSELECT_CHIP; }
//将数据写入写缓冲区 static void write_buffer(uint16_t addr,uint8_t *data,uint8_t size) { uint8_t i;
SELECT_CHIP;
spi_write(BUFFER_2_WRITE); spi_write(0x00); spi_write((uint8_t)(addr>>8)); spi_write((uint8_t)addr); for(i=0;ispi_write(data[i]);
UNSELECT_CHIP; }
/*****下面是为外部调用而提供的接口函数******/
void df_init(void) { //MISO设置为输入,上拉电阻关闭,其它默认为1 PORTB |= _BV(FLASH_SCK)|_BV(FLASH_MOSI)|_BV(FLASH_CS)|_BV(PB2);
//SCK,MOSI和CS端口对应脚设置为输出 DDRB |= _BV(FLASH_SCK)|_BV(FLASH_MOSI)|_BV(FLASH_CS);
// SPI中断禁止, SPI使能, master模式, MSB 前, SPI 模式 3, SCK频率Fcl/4 SPCR = _BV(SPE)|_BV(MSTR)|_BV(CPHA)|_BV(CPOL);//|_BV(SPR1)|_BV(SPR0); }
//读初始化功能函数,addr为打开后读到的初始地址 void df_read_open(uint32_t addr) { g_CurReadPage=addr/DF_PAGE_SIZE; g_CurReadByte=addr%DF_PAGE_SIZE; load_page_to_buffer(g_CurReadPage,DF_READ_BUFFER); }
void df_write_open(uint32_t addr) { g_CurWritePage=addr/DF_PAGE_SIZE; g_CurWriteByte=addr%DF_PAGE_SIZE; load_page_to_buffer(g_CurWritePage,DF_WRITE_BUFFER); }
uint8_t df_getc(void) { uint8_t c;
read_buffer(g_CurReadByte,&c,1); g_CurReadByte++; if(g_CurReadByte ==DF_PAGE_SIZE) { g_CurReadPage++; load_page_to_buffer(g_CurReadPage,DF_READ_BUFFER); g_CurReadByte=0; }
return c; }
void df_putc(uint8_t c) { write_buffer(g_CurWriteByte,&c,1); g_CurWriteByte++; if(g_CurWriteByte == DF_PAGE_SIZE) { g_CurWriteByte=0; write_page_from_buffer(g_CurWritePage,DF_WRITE_BUFFER); g_CurWritePage++; load_page_to_buffer(g_CurWritePage,DF_WRITE_BUFFER); } }
void df_read(uint8_t *buf,uint8_t size) { uint8_t temp;
if((g_CurReadByte + size) > DF_PAGE_SIZE) //如果当前页未读取数据不够size字节 { //读当前页剩余数据 temp=DF_PAGE_SIZE - g_CurReadByte; read_buffer(g_CurReadByte,buf,temp);
//装入下一页 load_page_to_buffer(++g_CurReadPage,DF_READ_BUFFER);
//从下一页读剩余数据 g_CurReadByte=size-temp; read_buffer(0,buf+temp,g_CurReadByte); } else //如果当前页数据有size字节 { read_buffer(g_CurReadByte,buf,size); g_CurReadByte+=size;
//如果当前页数据已全部读完 if(g_CurReadByte==DF_PAGE_SIZE) { load_page_to_buffer(++g_CurReadPage,DF_READ_BUFFER); g_CurReadByte=0; } } }
void df_write(uint8_t *buf,uint8_t size) { uint8_t temp;
if((g_CurWriteByte + size) > DF_PAGE_SIZE) //如果当前页未写空间不够size字节 { //写当前页剩余空间的数据 temp=DF_PAGE_SIZE - g_CurWriteByte; write_buffer(g_CurWriteByte,buf,temp); //保存当前页 write_page_from_buffer(g_CurWritePage,DF_WRITE_BUFFER); g_CurWritePage++; load_page_to_buffer(g_CurWritePage,DF_WRITE_BUFFER);
//写入到下一页对应缓冲区 g_CurWriteByte=size-temp; write_buffer(0,buf+temp,g_CurWriteByte); } else { write_buffer(g_CurWriteByte,buf,size); g_CurWriteByte+=size;
//缓冲已满,写入到主存储区 if(g_CurWriteByte==DF_PAGE_SIZE) { g_CurWriteByte=0; write_page_from_buffer(g_CurWritePage,DF_WRITE_BUFFER); g_CurWritePage++; load_page_to_buffer(g_CurWritePage,DF_WRITE_BUFFER); } } }
//调整写指针 void df_read_seek(uint32_t addr) { df_read_close(); df_read_open(addr); }
//调整读指针 void df_write_seek(uint32_t addr) { df_write_close(); df_write_open(addr); }
void df_read_close(void) { //此处不做任何处理 }
void df_write_close(void) { write_page_from_buffer(g_CurWritePage,DF_WRITE_BUFFER); //缓冲区内容写入到主存储器 }
dataflash.h文件:
#ifndef DATAFLASH_H #define DATAFLASH_H
//硬件引脚定义 #define FLASH_MOSI PB3 #define FLASH_MISO PB4 #define FLASH_SCK PB5 #define FLASH_CS PB1 #define UNSELECT_CHIP PORTB|=_BV(FLASH_CS) #define SELECT_CHIP PORTB&=~_BV(FLASH_CS)
// #define DF_PAGE_SIZE 528 #define DF_READ_BUFFER 0 #define DF_WRITE_BUFFER 1
#endif
测试电路图和实物照片:
|