📄 dataflash.c
字号:
/************************
AVR单片机SPI口读写at45db161d接口程序
文件名:dataflash.c
编译:WinAVR-20070525
设计思路:AT45DB161D内部有两个页缓冲BUFFER1和BUFFER2
本程序将它们分别用于读和写,当用户调用df_read_open函数时
将主存储器内的数据读到BUFFER1中,当用户调用df_getc或df_read时
从BUFFER1中给出要求长度的数据并对读进度进行记录,当读地址超出
当前页范围时向缓冲区装入下一页数据。
写入功能与读类似,但它使用BUFFER2.每更新一页时使用BUFFER到主
存储区的带擦除功能的命令,为此写之前不必考虑先擦器件。
调用示例:
//以下三行实现在1300地址处写入0xaa
df_write_open(1300);
df_putc(0xaa);
df_write_close();
//以下三行实现读出那1300处的一个字节数据
df_read_open(1300);
x=df_getc();
df_read_close();
注意事项:
1.尽量避免频繁调用df_write_open和df_write_close
如果写一组数据到指定地址,实现代码应当是这样的
df_write_open(xxx);
...写数据...
//一次操作中不论写多少字节都应当在这里完成
df_write_close();
而不是
for(i=xxx;i<nnn;i++)
{
df_write_open(xxx+i);
df_putc(buf[i]);
df_write_close();
}
2.df_read和df_write一次可读或写多个字节,它们比df_getc和df_putc
效率会高一些
芯艺设计室 2004-2007 版权所有
转载请保留本注释在内的全部内容
WEB: http://www.chipart.cn
Email: changfutong@sina.com
*******************************/
#include <avr/io.h>
#include "at45db161d.h"
#include "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;i<size;i++)
data[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;i<size;i++)
spi_write(data[i]);
UNSELECT_CHIP;
}
/*****下面是为外部调用而提供的接口函数******/
void df_init(void)
{
//MISO设置为输入,上拉电阻关闭,其它默认为1
PORTB |= _BV(FLASH_SCK)|_BV(FLASH_MOSI)|_BV(FLASH_CS)|_BV(PB2);
/*
注:使用AVR单片机SPI口,并用作主器件时SS引脚(ATMEGA8中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); //缓冲区内容写入到主存储器
}
//下面两个函数用于测试
/* //全片擦除
void df_erase(void)
{
uint16_t block_counter = 0;
while (block_counter < 512)
{
SELECT_CHIP;
spi_write(BLOCK_ERASE);
spi_write((uint8_t)(block_counter>>3));
spi_write((uint8_t)(block_counter<<5));
spi_write(0x00);
UNSELECT_CHIP;
block_counter++;
df_wait_busy();
}
}
*/
/*//读芯片ID
void df_read_deviceid(uint8_t *buf)
{
uint8_t i;
SELECT_CHIP;
spi_write(0x9f);
for(i=0;i<4;i++)
buf[i]=spi_write(0xff);
UNSELECT_CHIP;
}*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -