?? 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 + -